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.

2828 lines
88 KiB

  1. /* File: D:\WACKER\comstd\comstd.c (Created: 08-Dec-1993)
  2. *
  3. * Copyright 1994 by Hilgraeve Inc. -- Monroe, MI
  4. * All rights reserved
  5. *
  6. * $Revision: 35 $
  7. * $Date: 7/12/02 8:06a $
  8. */
  9. #define TAPI_CURRENT_VERSION 0x00010004 // cab:11/14/96 - required!
  10. #include <windows.h>
  11. #include <tapi.h>
  12. #include <unimodem.h>
  13. #include <time.h>
  14. #pragma hdrstop
  15. //#define DEBUGSTR
  16. //#define DEBUG_CHARDUMP
  17. #include <tdll\stdtyp.h>
  18. #include <tdll\session.h>
  19. #include <tdll\mc.h>
  20. #include <tdll\sf.h>
  21. #include <tdll\timers.h>
  22. #include <tdll\com.h>
  23. #include <tdll\comdev.h>
  24. #include "comstd.hh"
  25. #if defined(INCL_WINSOCK)
  26. #include <comwsock\comwsock.hh>
  27. #endif // defined(INCL_WINSOCK)
  28. #include <tdll\assert.h>
  29. #include <tdll\statusbr.h>
  30. #include <tdll\com.hh>
  31. #include "rc_id.h"
  32. #include <tdll\misc.h> // IsNT()
  33. #include <tdll\htchar.h>
  34. #include <tdll\cnct.h>
  35. #include <tdll\cnct.hh>
  36. #include <cncttapi\cncttapi.h>
  37. #include <cncttapi\cncttapi.hh>
  38. #if defined(DEBUG_CHARDUMP)
  39. #include <stdio.h>
  40. FILE *pfDbgR = NULL;
  41. FILE *pfDbgC = NULL;
  42. #endif
  43. BOOL WINAPI ComStdEntry(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpReserved);
  44. BOOL WINAPI _CRT_INIT(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpReserved);
  45. static void DeviceBreakTimerProc(void *pvData, long ulSince); //mrw:6/15/95
  46. HINSTANCE hinstDLL = (HINSTANCE)0;
  47. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  48. * FUNCTION:
  49. *
  50. * DESCRIPTION:
  51. * very temporary - mrw
  52. *
  53. * ARGUMENTS:
  54. *
  55. * RETURNS:
  56. *
  57. */
  58. int GetAutoDetect(ST_STDCOM *pstPrivate)
  59. {
  60. return pstPrivate->stWorkSettings.fAutoDetect;
  61. }
  62. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  63. * FUNCTION:
  64. * ComStdEntry
  65. *
  66. * DESCRIPTION:
  67. * Currently, just initializes the C-Runtime library but may be used
  68. * for other things later.
  69. *
  70. * ARGUMENTS:
  71. * hInstDll - Instance of this DLL
  72. * fdwReason - Why this entry point is called
  73. * lpReserved - reserved
  74. *
  75. * RETURNS:
  76. * BOOL
  77. *
  78. */
  79. BOOL WINAPI ComStdEntry(HINSTANCE hInst, DWORD fdwReason, LPVOID lpReserved)
  80. {
  81. hinstDLL = hInst;
  82. return _CRT_INIT(hInst, fdwReason, lpReserved);
  83. }
  84. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  85. * FUNCTION: DeviceInitialize
  86. *
  87. * DESCRIPTION:
  88. * Called whenever the driver is being loaded
  89. *
  90. * ARGUMENTS:
  91. * hCom -- A copy of the com handle. Can be used in the
  92. * driver code to call com services
  93. * usInterfaceVersion -- A version number identifying the version of the
  94. * driver interface
  95. * ppvDriverData -- A place to put the pointer to our private data.
  96. * This value will be passed back to us in all
  97. * subsequent calls.
  98. *
  99. * RETURNS:
  100. * COM_OK if all is hunky dory
  101. * COM_DEVICE_VERSION_ERROR if HA/Win expects a different interface version.
  102. * COM_NOT_ENOUGH_MEMORY
  103. * COM_DEVICE_ERROR if anything else goes wrong
  104. */
  105. int WINAPI DeviceInitialize(HCOM hCom,
  106. unsigned nInterfaceVersion,
  107. void **ppvDriverData)
  108. {
  109. int iRetVal = COM_OK;
  110. int ix;
  111. ST_STDCOM *pstPrivate = NULL;
  112. // Check version number and compatibility
  113. if (nInterfaceVersion != COM_VERSION)
  114. {
  115. // This error is reported by Com Routines. We cannot report errors
  116. // until after DeviceInitialize has completed.
  117. return COM_DEVICE_VERSION_ERROR;
  118. }
  119. if (*ppvDriverData)
  120. {
  121. pstPrivate = *ppvDriverData;
  122. }
  123. else
  124. {
  125. // Allocate our private storage structure
  126. if ((pstPrivate = malloc(sizeof(*pstPrivate))) == NULL)
  127. {
  128. return COM_NOT_ENOUGH_MEMORY;
  129. }
  130. *ppvDriverData = pstPrivate;
  131. // These members are common to both com drivers
  132. //
  133. pstPrivate->hCom = hCom;
  134. pstPrivate->fNotifyRcv = TRUE;
  135. pstPrivate->dwEventMask = 0;
  136. pstPrivate->fSending = FALSE;
  137. pstPrivate->lSndTimer = 0L;
  138. pstPrivate->lSndLimit = 0L;
  139. pstPrivate->lSndStuck = 0L;
  140. pstPrivate->hwndEvents = (HWND)0;
  141. pstPrivate->nRBufrSize = SIZE_INQ;
  142. pstPrivate->pbBufrStart = NULL;
  143. pstPrivate->fHaltThread = TRUE;
  144. InitializeCriticalSection(&pstPrivate->csect);
  145. for (ix = 0; ix < EVENT_COUNT; ++ix)
  146. {
  147. pstPrivate->ahEvent[ix] = CreateEvent(NULL,
  148. TRUE, // must be manually reset
  149. FALSE, // create unsignalled
  150. NULL); // unnamed
  151. if (pstPrivate->ahEvent[ix] == NULL)
  152. {
  153. iRetVal = COM_FAILED;
  154. //
  155. // Make sure to initialize the rest of the event handles to NULL;
  156. //
  157. for (++ix; ix < EVENT_COUNT; ++ix)
  158. {
  159. pstPrivate->ahEvent[ix] = NULL;
  160. }
  161. }
  162. }
  163. }
  164. // These members are specific to the stdcom driver
  165. //
  166. pstPrivate->bLastMdmStat = 0;
  167. pstPrivate->pbSndBufr = NULL;
  168. pstPrivate->nParityErrors = 0;
  169. pstPrivate->nFramingErrors = 0;
  170. pstPrivate->nOverrunErrors = 0;
  171. pstPrivate->nOverflowErrors = 0;
  172. pstPrivate->hWinComm = INVALID_HANDLE_VALUE;
  173. pstPrivate->fBreakSignalOn = FALSE;
  174. // Setup up reasonable default device values in case this type of
  175. // device has not been used in a session before
  176. pstPrivate->stWorkSettings.lBaud = 2400L;
  177. //pstPrivate->stWorkSettings.lBaud = 9600L;
  178. pstPrivate->stWorkSettings.nDataBits = 8;
  179. pstPrivate->stWorkSettings.nStopBits = ONESTOPBIT;
  180. pstPrivate->stWorkSettings.nParity = NOPARITY;
  181. pstPrivate->stWorkSettings.afHandshake = HANDSHAKE_RCV_RTS | HANDSHAKE_SND_CTS;
  182. pstPrivate->stWorkSettings.chXON = 0x11;
  183. pstPrivate->stWorkSettings.chXOFF = 0x13;
  184. pstPrivate->stWorkSettings.nBreakDuration = 750;
  185. pstPrivate->stWorkSettings.fAutoDetect = TRUE;
  186. pstPrivate->stFileSettings = pstPrivate->stWorkSettings;
  187. pstPrivate->fADRunning = FALSE;
  188. pstPrivate->nADTotal = 0;
  189. pstPrivate->nADMix = 0;
  190. pstPrivate->nAD7o1 = 0;
  191. pstPrivate->nADHighBits = 0;
  192. pstPrivate->nADBestGuess = AD_DONT_KNOW;
  193. pstPrivate->chADLastChar = '\0';
  194. pstPrivate->fADToggleParity = FALSE;
  195. pstPrivate->fADReconfigure = FALSE;
  196. pstPrivate->hComstdThread = NULL;
  197. if (iRetVal != COM_OK)
  198. {
  199. if (pstPrivate)
  200. {
  201. free(pstPrivate);
  202. pstPrivate = NULL;
  203. }
  204. }
  205. return iRetVal;
  206. }
  207. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  208. * FUNCTION: DeviceClose
  209. *
  210. * DESCRIPTION:
  211. * Called when HA/Win is done with this driver and is about to release .DLL
  212. *
  213. * ARGUMENTS:
  214. * pstPrivate -- Pointer to our private data structure
  215. *
  216. * RETURNS:
  217. * COM_OK
  218. */
  219. int WINAPI DeviceClose(ST_STDCOM *pstPrivate)
  220. {
  221. int ix;
  222. // Driver is about to be let go, do any cleanup
  223. // Port should have been deactivated before we are called, but
  224. // check anyway.
  225. PortDeactivate(pstPrivate);
  226. for (ix = 0; ix < EVENT_COUNT; ++ix)
  227. {
  228. if (pstPrivate->ahEvent[ix])
  229. {
  230. ResetEvent(pstPrivate->ahEvent[ix]);
  231. CloseHandle(pstPrivate->ahEvent[ix]);
  232. pstPrivate->ahEvent[ix] = NULL;
  233. }
  234. }
  235. DeleteCriticalSection(&pstPrivate->csect);
  236. // Free our private data area
  237. free(pstPrivate);
  238. pstPrivate = NULL;
  239. return COM_OK;
  240. }
  241. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  242. * FUNCTION:
  243. * ComLoadStdcomDriver
  244. *
  245. * DESCRIPTION:
  246. * Loads the COM handle with pointers to the stdcom driver functions
  247. *
  248. * ARGUMENTS:
  249. *
  250. * RETURNS:
  251. * COM_OK if successful
  252. * COM_FAILED otherwise
  253. *
  254. * AUTHOR:
  255. * mcc 12/26/95
  256. */
  257. int ComLoadStdcomDriver(HCOM pstCom)
  258. {
  259. int iRetVal = COM_OK;
  260. if ( !pstCom )
  261. return COM_FAILED;
  262. pstCom->pfPortActivate = PortActivate;
  263. pstCom->pfPortDeactivate = PortDeactivate;
  264. pstCom->pfPortConnected = PortConnected;
  265. pstCom->pfRcvRefill = RcvRefill;
  266. pstCom->pfRcvClear = RcvClear;
  267. pstCom->pfSndBufrSend = SndBufrSend;
  268. pstCom->pfSndBufrIsBusy = SndBufrIsBusy;
  269. pstCom->pfSndBufrClear = SndBufrClear;
  270. pstCom->pfSndBufrQuery = SndBufrQuery;
  271. pstCom->pfDeviceSpecial = DeviceSpecial;
  272. pstCom->pfPortConfigure = PortConfigure;
  273. pstCom->pfDeviceDialog = DeviceDialog;
  274. return iRetVal;
  275. }
  276. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  277. * FUNCTION: DeviceDialog
  278. *
  279. * DESCRIPTION:
  280. *
  281. *
  282. * ARGUMENTS:
  283. *
  284. *
  285. * RETURNS:
  286. *
  287. */
  288. /*lint ARGSUSED*/
  289. int WINAPI DeviceDialog(ST_STDCOM *pstPrivate, HWND hwndParent)
  290. {
  291. int iRetValue = COM_OK;
  292. COMMCONFIG stCC;
  293. TCHAR szPortName[COM_MAX_PORT_NAME];
  294. memset(&stCC, 0, sizeof(stCC));
  295. stCC.dwSize = sizeof(stCC);
  296. stCC.wVersion = 1;
  297. stCC.dwProviderSubType = PST_RS232;
  298. ComGetPortName(pstPrivate->hCom, szPortName, COM_MAX_PORT_NAME);
  299. ComstdSettingsToDCB(&pstPrivate->stWorkSettings, &stCC.dcb);
  300. if (CommConfigDialog(szPortName, hwndParent, &stCC))
  301. {
  302. ComstdDCBToSettings(&stCC.dcb, &pstPrivate->stWorkSettings);
  303. }
  304. else
  305. {
  306. iRetValue = COM_CANCELLED;
  307. //DbgShowLastError();
  308. }
  309. return iRetValue;
  310. }
  311. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  312. * FUNCTION: DeviceGetCommon
  313. *
  314. * DESCRIPTION:
  315. * Gets user settings common to all drivers
  316. *
  317. * ARGUMENTS:
  318. * pstPrivate -- Our private data structure
  319. * pstcommon -- Pointer to structure of type ST_COMMON to be filled in
  320. * with the desired settings
  321. *
  322. * RETURNS:
  323. * Always returns COM_OK
  324. */
  325. int WINAPI DeviceGetCommon(ST_STDCOM *pstPrivate, ST_COMMON *pstCommon)
  326. {
  327. pstCommon->afItem = (COM_BAUD |
  328. COM_DATABITS |
  329. COM_STOPBITS |
  330. COM_PARITY |
  331. COM_AUTO);
  332. pstCommon->lBaud = pstPrivate->stWorkSettings.lBaud;
  333. pstCommon->nDataBits = pstPrivate->stWorkSettings.nDataBits;
  334. pstCommon->nStopBits = pstPrivate->stWorkSettings.nStopBits;
  335. pstCommon->nParity = pstPrivate->stWorkSettings.nParity;
  336. pstCommon->fAutoDetect = pstPrivate->stWorkSettings.fAutoDetect;
  337. return COM_OK;
  338. }
  339. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  340. * FUNCTION: DeviceSetCommon
  341. *
  342. * DESCRIPTION:
  343. * Passes common user settings to driver for use and storage.
  344. *
  345. * ARGUMENTS:
  346. * pstPrivate
  347. * pstCommon -- Structure containing common user settings to be used
  348. * by driver
  349. *
  350. * RETURNS:
  351. * Always returns COM_OK
  352. */
  353. int WINAPI DeviceSetCommon(ST_STDCOM *pstPrivate, ST_COMMON *pstCommon)
  354. {
  355. if (bittest(pstCommon->afItem, COM_BAUD))
  356. pstPrivate->stWorkSettings.lBaud = pstCommon->lBaud;
  357. if (bittest(pstCommon->afItem, COM_DATABITS))
  358. pstPrivate->stWorkSettings.nDataBits = pstCommon->nDataBits;
  359. if (bittest(pstCommon->afItem, COM_STOPBITS))
  360. pstPrivate->stWorkSettings.nStopBits = pstCommon->nStopBits;
  361. if (bittest(pstCommon->afItem, COM_PARITY))
  362. pstPrivate->stWorkSettings.nParity = pstCommon->nParity;
  363. if (bittest(pstCommon->afItem, COM_AUTO))
  364. pstPrivate->stWorkSettings.fAutoDetect = pstCommon->fAutoDetect;
  365. return COM_OK;
  366. }
  367. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  368. * FUNCTION: DeviceSpecial
  369. *
  370. * DESCRIPTION:
  371. * The means for others to control any special features in this driver
  372. * that are not supported by all drivers.
  373. *
  374. * ARGUMENTS:
  375. *
  376. *
  377. * RETURNS:
  378. * COM_NOT_SUPPORTED if the instruction string was not recognized
  379. * otherwise depends on instruction string
  380. */
  381. /*ARGSUSED*/
  382. int WINAPI DeviceSpecial(ST_STDCOM *pstPrivate,
  383. const TCHAR *pszInstructions,
  384. TCHAR *pszResult,
  385. int nBufrSize)
  386. {
  387. int iRetVal = COM_NOT_SUPPORTED;
  388. HSESSION hSession;
  389. #if 0 //* do port of this later
  390. unsigned usMask = 0;
  391. unsigned long ulSetVal;
  392. TCHAR *pszEnd;
  393. //
  394. // MAX_IP_ADDR_LEN+11+1 = buffer size of pstPrivate->szRemoteAddr +
  395. // settings string "SET IPADDR=" + 1 for the terminating NULL
  396. // character. REV 09/20/2000
  397. //
  398. TCHAR achInstructions[MAX_IP_ADDR_LEN+11+1]; // John: decide how you want to handle
  399. TCHAR *pszToken = achInstructions;
  400. int iIndex;
  401. TCHAR szResult[MAX_IP_ADDR_LEN+11+1];
  402. static TCHAR *apszItems[] =
  403. {
  404. "HANDSHAKE_RCV_X",
  405. "HANDSHAKE_RCV_DTR",
  406. "HANDSHAKE_RCV_RTS",
  407. "HANDSHAKE_SND_X",
  408. "HANDSHAKE_SND_CTS",
  409. "HANDSHAKE_SND_DSR",
  410. "HANDSHAKE_SND_DCD",
  411. "XON_CHAR",
  412. "XOFF_CHAR",
  413. "BREAK_DURATION",
  414. "CTS_STATUS",
  415. "DSR_STATUS",
  416. "DCD_STATUS",
  417. "DTR_STATE",
  418. "RTS_STATE",
  419. "MODIFIED", // remove when real temporary settings are in
  420. NULL
  421. };
  422. // supported instruction strings:
  423. // "Set xxx=vv"
  424. // "Query xxx"
  425. if (!pszInstructions || !*pszInstructions)
  426. return COM_FAILED;
  427. if (sizeof(achInstructions) < (size_t)(StrCharGetStrLength(pszInstructions) + 1))
  428. return COM_NOT_SUPPORTED;
  429. strcpy(achInstructions, pszInstructions);
  430. if (pszResult)
  431. *pszResult = TEXT('\0');
  432. pszToken = strtok(achInstructions, " ");
  433. if (!pszToken)
  434. return COM_NOT_SUPPORTED;
  435. if (StrCharCmpi(pszToken, "SET") == 0)
  436. {
  437. iRetVal = COM_OK;
  438. pszToken = strtok(NULL, " =");
  439. if (!pszToken)
  440. pszToken = TEXT('\0');
  441. // Look up the item to set
  442. for (iIndex = 0; apszItems[iIndex]; ++iIndex)
  443. if (StrCharCmpi(pszToken, apszItems[iIndex]) == 0)
  444. break;
  445. // Isolate the new value to be set
  446. pszToken = strtok(NULL, "\n");
  447. if (pszToken && *pszToken)
  448. {
  449. // Several items take numeric values
  450. ulSetVal = strtoul(pszToken, &pszEnd, 0);
  451. switch(iIndex)
  452. {
  453. case 0: // RCV_X
  454. usMask = HANDSHAKE_RCV_X;
  455. break;
  456. case 1: // RCV_DTR
  457. usMask = HANDSHAKE_RCV_DTR;
  458. break;
  459. case 2: // RCV_RTS
  460. usMask = HANDSHAKE_RCV_RTS;
  461. break;
  462. case 3: // SND_X
  463. usMask = HANDSHAKE_SND_X;
  464. break;
  465. case 4: // SND_CTS
  466. usMask = HANDSHAKE_SND_CTS;
  467. break;
  468. case 5: // SND_DSR
  469. usMask = HANDSHAKE_SND_DSR;
  470. break;
  471. case 6: // SND_DCD
  472. usMask = HANDSHAKE_SND_DCD;
  473. break;
  474. case 7: // XON_CHAR
  475. if (!*pszEnd && ulSetVal <= UCHAR_MAX)
  476. pstPrivate->stWorkSettings.chXON = (TCHAR)ulSetVal;
  477. else
  478. iRetVal = COM_FAILED;
  479. break;
  480. case 8: // XOFF_CHAR
  481. if (!*pszEnd && ulSetVal <= UCHAR_MAX)
  482. pstPrivate->stWorkSettings.chXOFF = (TCHAR)ulSetVal;
  483. else
  484. iRetVal = COM_FAILED;
  485. break;
  486. case 9: // BREAK_DURATION
  487. if (!*pszEnd && ulSetVal <= USHRT_MAX)
  488. pstPrivate->stWorkSettings.nBreakDuration = (USHORT)ulSetVal;
  489. else
  490. iRetVal = COM_FAILED;
  491. break;
  492. case 13: // DTR_STATE
  493. if (pstPrivate->hWinComm != INVALID_HANDLE_VALUE)
  494. {
  495. switch (ulSetVal)
  496. {
  497. case 0:
  498. EscapeCommFunction(pstPrivate->hWinComm, CLRDTR);
  499. break;
  500. case 1:
  501. EscapeCommFunction(pstPrivate->hWinComm, SETDTR);
  502. break;
  503. default:
  504. iRetVal = COM_FAILED;
  505. break;
  506. }
  507. }
  508. else
  509. iRetVal = COM_PORT_NOT_OPEN;
  510. break;
  511. case 14: // RTS_STATE
  512. if (pstPrivate->hWinComm != INVALID_HANDLE_VALUE)
  513. {
  514. switch (ulSetVal)
  515. {
  516. case 0:
  517. EscapeCommFunction(pstPrivate->hWinComm, CLRRTS);
  518. break;
  519. case 1:
  520. EscapeCommFunction(pstPrivate->hWinComm, SETRTS);
  521. break;
  522. default:
  523. iRetVal = COM_FAILED;
  524. break;
  525. }
  526. }
  527. else
  528. iRetVal = COM_PORT_NOT_OPEN;
  529. break;
  530. // TODO: remove when real temp settings are implemented
  531. case 15: // MODIFIED
  532. break;
  533. default: // Who was that masked man?
  534. iRetVal = COM_FAILED;
  535. break;
  536. }
  537. if (usMask != 0)
  538. {
  539. // Must have been a handshake setting
  540. if (strcmp(pszToken, "1") == 0)
  541. bitset(pstPrivate->stWorkSettings.afHandshake, usMask);
  542. else if (strcmp(pszToken, "0") == 0)
  543. bitclear(pstPrivate->stWorkSettings.afHandshake,usMask);
  544. else
  545. {
  546. iRetVal = COM_FAILED;
  547. }
  548. }
  549. }
  550. else // if (pszToken && *pszToken)
  551. {
  552. iRetVal = COM_NOT_SUPPORTED;
  553. }
  554. }
  555. else if (StrCharCmpi(pszToken, "QUERY") == 0)
  556. {
  557. iRetVal = COM_OK;
  558. pszToken = strtok(NULL, "\n");
  559. szResult[0] = TEXT('\0');
  560. // Look up the item to query
  561. for (iIndex = 0; apszItems[iIndex]; ++iIndex)
  562. if (StrCharCmpi(pszToken, apszItems[iIndex]) == 0)
  563. break;
  564. if (*pszToken)
  565. {
  566. switch(iIndex)
  567. {
  568. case 0: // RCV_X
  569. usMask = HANDSHAKE_RCV_X;
  570. break;
  571. case 1: // RCV_DTR
  572. usMask = HANDSHAKE_RCV_DTR;
  573. break;
  574. case 2: // RCV_RTS
  575. usMask = HANDSHAKE_RCV_RTS;
  576. break;
  577. case 3: // SND_X
  578. usMask = HANDSHAKE_SND_X;
  579. break;
  580. case 4: // SND_CTS
  581. usMask = HANDSHAKE_SND_CTS;
  582. break;
  583. case 5: // SND_DSR
  584. usMask = HANDSHAKE_SND_DSR;
  585. break;
  586. case 6: // SND_DCD
  587. usMask = HANDSHAKE_SND_DCD;
  588. break;
  589. case 7: // XON_CHAR
  590. wsprintf(szResult, "%u", pstPrivate->stWorkSettings.chXON);
  591. break;
  592. case 8: // XOFF_CHAR
  593. wsprintf(szResult, "%u", pstPrivate->stWorkSettings.chXOFF);
  594. break;
  595. case 9: // BREAK_DURATION
  596. wsprintf(szResult, "%u", pstPrivate->stWorkSettings.nBreakDuration);
  597. break;
  598. case 10: // CTS_STATUS
  599. strcpy(szResult, bittest(*pbMdmStat, MDMSTAT_CTS) ? "1" : "0");
  600. break;
  601. case 11: // DSR_STATUS
  602. strcpy(szResult, bittest(*pbMdmStat, MDMSTAT_DSR) ? "1" : "0");
  603. break;
  604. case 12: // DCD_STATUS
  605. strcpy(szResult, bittest(*pbMdmStat, MDMSTAT_DCD) ? "1" : "0");
  606. break;
  607. case 15: // MODIFIED
  608. strcpy(szResult, "0");
  609. break;
  610. default: // Who was that masked man?
  611. iRetVal = COM_FAILED;
  612. break;
  613. }
  614. if (usMask != 0)
  615. {
  616. // Must have been a handshake setting
  617. strcpy(szResult,
  618. bittest(pstPrivate->stWorkSettings.afHandshake, usMask) ? "1" : "0");
  619. }
  620. if (szResult[0])
  621. {
  622. if (!pszResult || strlen(szResult) > uiBufrSize)
  623. iRetVal = COM_FAILED;
  624. else
  625. strcpy(pszResult, szResult);
  626. }
  627. }
  628. }
  629. else if (StrCharCmpi(pszToken, "SEND") == 0)
  630. {
  631. pszToken = strtok(NULL, "\n");
  632. if (StrCharCmpi(pszToken, "BREAK") == 0)
  633. {
  634. if (pstPrivate->hWinComm != INVALID_HANDLE_VALUE && !pstPrivate->fBreakSignalOn)
  635. {
  636. SndBufrClear(pstPrivate);
  637. SetCommBreak(pstPrivate->hWinComm);
  638. ComGetSession(pstPrivate->hCom, &hSession);
  639. if (TimerCreate(hSession,
  640. &pstPrivate->hTmrBreak,
  641. pstPrivate->stWorkSettings.nBreakDuration,
  642. MakeProcInstance((FARPROC)DeviceBreakTimerProc, hinstDLL),
  643. (DWORD)pstPrivate) != TIMER_OK)
  644. {
  645. //* DeviceReportError(pstPrivate, SID_ERR_NOTIMER, 0, TRUE);
  646. iRetVal = COM_DEVICE_ERROR;
  647. }
  648. pstPrivate->fBreakSignalOn = TRUE;
  649. iRetVal = COM_OK;
  650. }
  651. }
  652. }
  653. #else
  654. if (pszResult && nBufrSize > 0)
  655. {
  656. *pszResult = TEXT('\0');
  657. }
  658. #endif
  659. // Implement only the Break function. All other comm functions handled
  660. // through TAPI. - mrw:6/15/95
  661. //
  662. if (StrCharCmpi(pszInstructions, "Send Break") == 0)
  663. {
  664. if (pstPrivate->hWinComm != INVALID_HANDLE_VALUE && !pstPrivate->fBreakSignalOn)
  665. {
  666. SndBufrClear(pstPrivate);
  667. SetCommBreak(pstPrivate->hWinComm);
  668. ComGetSession(pstPrivate->hCom, &hSession);
  669. if (TimerCreate(hSession,
  670. &pstPrivate->hTmrBreak,
  671. pstPrivate->stWorkSettings.nBreakDuration,
  672. DeviceBreakTimerProc,
  673. pstPrivate) != TIMER_OK)
  674. {
  675. //* DeviceReportError(pstPrivate, SID_ERR_NOTIMER, 0, TRUE);
  676. iRetVal = COM_DEVICE_ERROR;
  677. }
  678. pstPrivate->fBreakSignalOn = TRUE;
  679. iRetVal = COM_OK;
  680. }
  681. }
  682. //
  683. // This is necessary to detect loss of carrier on COM ports. REV: 08/22/2001
  684. //
  685. else if (StrCharCmpi(pszInstructions, "Query DCD_STATUS") == 0)
  686. {
  687. iRetVal = COM_OK;
  688. if (pszResult && nBufrSize > 0)
  689. {
  690. _itoa(PortConnected(pstPrivate), pszResult, 10);
  691. }
  692. }
  693. //
  694. // This is necessary to get the default settings on COM ports. REV: 08/22/2001
  695. //
  696. else if (StrCharCmpi(pszInstructions, "GET Defaults") == 0)
  697. {
  698. iRetVal = PortDefaultSettings(pstPrivate);
  699. }
  700. return iRetVal;
  701. }
  702. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  703. * FUNCTION:
  704. * DeviceLoadHdl
  705. *
  706. * DESCRIPTION:
  707. *
  708. *
  709. * ARGUMENTS:
  710. * pstPrivate -- driver data structure
  711. *
  712. * RETURNS:
  713. *
  714. */
  715. int WINAPI DeviceLoadHdl(ST_STDCOM *pstPrivate, SF_HANDLE sfHdl)
  716. {
  717. unsigned long ul;
  718. // Load comm settings from the session file. If we connect via TAPI,
  719. // several of these settings will be inherited from TAPI and these
  720. // values will not be used.
  721. ul = sizeof(pstPrivate->stWorkSettings.lBaud);
  722. sfGetSessionItem(sfHdl, SFID_COMSTD_BAUD, &ul,
  723. &pstPrivate->stWorkSettings.lBaud);
  724. ul = sizeof(pstPrivate->stWorkSettings.nDataBits);
  725. sfGetSessionItem(sfHdl, SFID_COMSTD_DATABITS, &ul,
  726. &pstPrivate->stWorkSettings.nDataBits);
  727. ul = sizeof(pstPrivate->stWorkSettings.nStopBits);
  728. sfGetSessionItem(sfHdl, SFID_COMSTD_STOPBITS, &ul,
  729. &pstPrivate->stWorkSettings.nStopBits);
  730. ul = sizeof(pstPrivate->stWorkSettings.nParity);
  731. sfGetSessionItem(sfHdl, SFID_COMSTD_PARITY, &ul,
  732. &pstPrivate->stWorkSettings.nParity);
  733. ul = sizeof(pstPrivate->stWorkSettings.afHandshake);
  734. sfGetSessionItem(sfHdl, SFID_COMSTD_HANDSHAKING, &ul,
  735. &pstPrivate->stWorkSettings.afHandshake);
  736. ul = sizeof(pstPrivate->stWorkSettings.fAutoDetect);
  737. sfGetSessionItem(sfHdl, SFID_COMSTD_AUTODETECT, &ul,
  738. &pstPrivate->stWorkSettings.fAutoDetect);
  739. return SF_OK;
  740. }
  741. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  742. * FUNCTION:
  743. * DeviceSaveHdl
  744. *
  745. * DESCRIPTION:
  746. *
  747. *
  748. * ARGUMENTS:
  749. * pstPrivate -- driver data structure
  750. *
  751. * RETURNS:
  752. *
  753. */
  754. int WINAPI DeviceSaveHdl(ST_STDCOM *pstPrivate, SF_HANDLE sfHdl)
  755. {
  756. // Save settings in session file space. Many of these values may be
  757. // overwritten by TAPI settings but are used by direct connect.
  758. sfPutSessionItem(sfHdl, SFID_COMSTD_BAUD,
  759. sizeof(pstPrivate->stWorkSettings.lBaud),
  760. &pstPrivate->stWorkSettings.lBaud);
  761. sfPutSessionItem(sfHdl, SFID_COMSTD_DATABITS,
  762. sizeof(pstPrivate->stWorkSettings.nDataBits),
  763. &pstPrivate->stWorkSettings.nDataBits);
  764. sfPutSessionItem(sfHdl, SFID_COMSTD_STOPBITS,
  765. sizeof(pstPrivate->stWorkSettings.nStopBits),
  766. &pstPrivate->stWorkSettings.nStopBits);
  767. sfPutSessionItem(sfHdl, SFID_COMSTD_PARITY,
  768. sizeof(pstPrivate->stWorkSettings.nParity),
  769. &pstPrivate->stWorkSettings.nParity);
  770. sfPutSessionItem(sfHdl, SFID_COMSTD_HANDSHAKING,
  771. sizeof(pstPrivate->stWorkSettings.afHandshake),
  772. &pstPrivate->stWorkSettings.afHandshake);
  773. sfPutSessionItem(sfHdl, SFID_COMSTD_AUTODETECT,
  774. sizeof(pstPrivate->stWorkSettings.fAutoDetect),
  775. &pstPrivate->stWorkSettings.fAutoDetect);
  776. return SF_OK;
  777. }
  778. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  779. * FUNCTION: PortActivate
  780. *
  781. * DESCRIPTION:
  782. * Called to activate the port and open it for use
  783. *
  784. * ARGUMENTS:
  785. * pstPrivate -- driver data structure
  786. * pszPortName -- the name of the port to activate
  787. *
  788. * RETURNS:
  789. * COM_OK if port is successfully activated
  790. * COM_NOT_ENOUGH_MEMORY if there in insufficient memory for data storage
  791. * COM_NOT_FOUND if named port cannot be opened
  792. * COM_DEVICE_ERROR if API errors are encountered
  793. */
  794. int WINAPI PortActivate(ST_STDCOM *pstPrivate,
  795. TCHAR *pszPortName,
  796. DWORD_PTR dwMediaHdl)
  797. {
  798. TCHAR szFullPortName[MAX_PATH];
  799. int iRetVal = COM_OK;
  800. ST_COM_CONTROL *pstComCntrl;
  801. DWORD dwThreadID;
  802. //
  803. // Free the send bufers prior to setting to malloc so we don't
  804. // have a memory leak. REV: 02/27/2001.
  805. //
  806. if (pstPrivate->pbBufrStart)
  807. {
  808. free(pstPrivate->pbBufrStart);
  809. pstPrivate->pbBufrStart = NULL;
  810. }
  811. // Make sure we can get enough memory for buffers before opening device
  812. pstPrivate->pbBufrStart = malloc((size_t)pstPrivate->nRBufrSize);
  813. if (pstPrivate->pbBufrStart == NULL)
  814. {
  815. iRetVal = COM_NOT_ENOUGH_MEMORY;
  816. //* DeviceReportError(pstPrivate, SID_ERR_NOMEM, 0, TRUE);
  817. goto checkout;
  818. }
  819. //
  820. // Free the send bufers prior to setting to malloc so we don't
  821. // have a memory leak. REV: 02/27/2001.
  822. //
  823. if (pstPrivate->pbSndBufr)
  824. {
  825. free(pstPrivate->pbSndBufr);
  826. pstPrivate->pbSndBufr = NULL;
  827. }
  828. pstPrivate->pbSndBufr = malloc((size_t) SIZE_OUTQ);
  829. if (pstPrivate->pbSndBufr == 0)
  830. {
  831. iRetVal = COM_NOT_ENOUGH_MEMORY;
  832. free(pstPrivate->pbBufrStart);
  833. pstPrivate->pbBufrStart = NULL;
  834. goto checkout;
  835. }
  836. pstPrivate->pbBufrEnd = pstPrivate->pbBufrStart + pstPrivate->nRBufrSize;
  837. pstPrivate->pbReadEnd = pstPrivate->pbBufrStart;
  838. pstPrivate->pbComStart = pstPrivate->pbComEnd = pstPrivate->pbBufrStart;
  839. pstPrivate->fBufrEmpty = TRUE;
  840. #if defined(DEBUG_CHARDUMP)
  841. if (!pfDbgR)
  842. pfDbgR = fopen("comreads.dbg", "wt");
  843. fprintf(pfDbgR, "Port opened, internal buffer = 0x%p to 0x%p\n",
  844. pstPrivate->pbBufrStart, pstPrivate->pbBufrEnd - 1);
  845. if (!pfDbgC)
  846. pfDbgC = fopen("comused.dbg", "wt");
  847. fprintf(pfDbgC, "Port opened, internal buffer = 0x%p to 0x%p\n",
  848. pstPrivate->pbBufrStart, pstPrivate->pbBufrEnd - 1);
  849. #endif
  850. pstPrivate->dwSndOffset = 0;
  851. pstPrivate->dwBytesToSend = 0;
  852. if (dwMediaHdl)
  853. {
  854. pstPrivate->hWinComm = (HANDLE)dwMediaHdl;
  855. if (PortExtractSettings(pstPrivate) != COM_OK)
  856. iRetVal = COM_DEVICE_ERROR;
  857. }
  858. else
  859. {
  860. // Win32 internally maps ports COM1 to COM9 to
  861. // \\.\COMx. We need to add this for ports COMxx,
  862. // and for special com devices in the registry.
  863. //
  864. StrCharCopyN(szFullPortName, TEXT("\\\\.\\"), sizeof(szFullPortName) / sizeof(TCHAR));
  865. StrCharCat(szFullPortName, pszPortName);
  866. pstPrivate->hWinComm = CreateFile(szFullPortName,
  867. GENERIC_READ | GENERIC_WRITE,
  868. 0,
  869. (LPSECURITY_ATTRIBUTES)NULL,
  870. OPEN_EXISTING,
  871. FILE_FLAG_OVERLAPPED,
  872. (HANDLE)NULL);
  873. if (pstPrivate->hWinComm == INVALID_HANDLE_VALUE)
  874. {
  875. //* Figure out which errors to report specifically
  876. DWORD dwError = GetLastError();
  877. if( dwError == ERROR_NOT_ENOUGH_MEMORY ||
  878. dwError == ERROR_OUTOFMEMORY ||
  879. dwError == ERROR_OUT_OF_STRUCTURES ||
  880. dwError == ERROR_INSUFFICIENT_BUFFER ||
  881. dwError == ERROR_COMMITMENT_LIMIT ||
  882. dwError == ERROR_NOT_ENOUGH_QUOTA)
  883. {
  884. iRetVal = COM_NOT_ENOUGH_MEMORY;
  885. }
  886. else if(dwError == ERROR_ACCESS_DENIED ||
  887. dwError == ERROR_SHARING_VIOLATION ||
  888. dwError == ERROR_LOCK_VIOLATION ||
  889. dwError == ERROR_OPEN_FAILED ||
  890. dwError == ERROR_IRQ_BUSY ||
  891. dwError == ERROR_DEVICE_IN_USE)
  892. {
  893. iRetVal = COM_PORT_IN_USE;
  894. }
  895. else
  896. {
  897. iRetVal = COM_NOT_FOUND;
  898. }
  899. }
  900. }
  901. if (iRetVal == COM_OK)
  902. {
  903. // Major bug in Win95 - If you call SetupComm() for a standard
  904. // comm handle (not one given to us by TAPI) the WriteFile
  905. // call fails and locks the system. - mrw:2/29/96
  906. //
  907. if (IsNT() && SetupComm(pstPrivate->hWinComm, 8192, 8192) == FALSE)
  908. {
  909. assert(0);
  910. }
  911. }
  912. if (iRetVal == COM_OK)
  913. {
  914. iRetVal = PortConfigure(pstPrivate);
  915. }
  916. if (iRetVal == COM_OK)
  917. {
  918. pstComCntrl = (ST_COM_CONTROL *)pstPrivate->hCom;
  919. pstComCntrl->puchRBData = pstPrivate->pbBufrStart;
  920. pstComCntrl->puchRBDataLimit = pstPrivate->pbBufrStart;
  921. pstPrivate->dwEventMask = EV_ERR | EV_RLSD;
  922. pstPrivate->fNotifyRcv = TRUE;
  923. pstPrivate->fBufrEmpty = TRUE;
  924. if (!SetCommMask(pstPrivate->hWinComm, pstPrivate->dwEventMask))
  925. iRetVal = COM_DEVICE_ERROR;
  926. // Clear error counts on new connection
  927. pstPrivate->nParityErrors = 0;
  928. pstPrivate->nFramingErrors = 0;
  929. pstPrivate->nOverrunErrors = 0;
  930. pstPrivate->nOverflowErrors = 0;
  931. // Start thread to handle Reading, Writing (& 'rithmetic) & events
  932. pstPrivate->fHaltThread = FALSE;
  933. DBG_THREAD("DBG_THREAD: Calling CreateThread\r\n",0,0,0,0,0);
  934. pstPrivate->hComstdThread = CreateThread((LPSECURITY_ATTRIBUTES)0,
  935. 2000, ComstdThread, pstPrivate, 0, &dwThreadID);
  936. if (pstPrivate->hComstdThread)
  937. {
  938. SetThreadPriority(pstPrivate->hComstdThread,
  939. THREAD_PRIORITY_ABOVE_NORMAL);
  940. //THREAD_PRIORITY_TIME_CRITICAL); // - mrw:7/8/96
  941. }
  942. DBG_THREAD("DBG_THREAD: CreateThread returned %08X\r\n",
  943. pstPrivate->hComstdThread,0,0,0,0);
  944. }
  945. checkout:
  946. if (iRetVal != COM_OK)
  947. PortDeactivate(pstPrivate);
  948. return iRetVal;
  949. }
  950. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  951. * FUNCTION: PortDeactivate
  952. *
  953. * DESCRIPTION:
  954. * Deactivates and closes an open port
  955. *
  956. * ARGUMENTS:
  957. * pstPrivate -- Driver data structure
  958. *
  959. * RETURNS:
  960. * COM_OK
  961. */
  962. int WINAPI PortDeactivate(ST_STDCOM *pstPrivate)
  963. {
  964. int iRetVal = COM_OK;
  965. if (pstPrivate->hComstdThread)
  966. {
  967. DWORD dwResult = 0L;
  968. // Halt the thread by setting a flag for the thread to detect and then
  969. // forcing WaitCommEvent to return by changing the event mask
  970. DBG_THREAD("DBG_THREAD: Shutting down comstd thread\r\n", 0,0,0,0,0);
  971. pstPrivate->fHaltThread = TRUE;
  972. SetCommMask(pstPrivate->hWinComm, pstPrivate->dwEventMask);
  973. PurgeComm(pstPrivate->hWinComm,
  974. PURGE_TXABORT | PURGE_RXABORT); // Abort any calls in progress
  975. // thread should exit now, it's handle will signal when it has exited
  976. if (pstPrivate->hComstdThread)
  977. {
  978. dwResult = WaitForSingleObject(pstPrivate->hComstdThread, 5000);
  979. if (dwResult != WAIT_OBJECT_0)
  980. {
  981. if (dwResult == WAIT_FAILED)
  982. {
  983. dwResult = GetLastError();
  984. }
  985. assert(FALSE);
  986. }
  987. }
  988. if (pstPrivate->hComstdThread)
  989. {
  990. CloseHandle(pstPrivate->hComstdThread);
  991. pstPrivate->hComstdThread = NULL;
  992. DBG_THREAD("DBG_THREAD: Comstd thread has shut down\r\n", 0,0,0,0,0);
  993. }
  994. }
  995. if (pstPrivate->pbBufrStart)
  996. {
  997. free(pstPrivate->pbBufrStart);
  998. pstPrivate->pbBufrStart = NULL;
  999. }
  1000. if (pstPrivate->pbSndBufr)
  1001. {
  1002. free(pstPrivate->pbSndBufr);
  1003. pstPrivate->pbSndBufr = 0;
  1004. }
  1005. if (pstPrivate->hWinComm != INVALID_HANDLE_VALUE)
  1006. {
  1007. //* As of 2/9/94, this PurgeComm call caused the program to hang
  1008. // or reboot
  1009. // PurgeComm(pstPrivate->hWinComm,
  1010. // PURGE_TXABORT | PURGE_RXABORT); // Flush transmit queue
  1011. CloseHandle(pstPrivate->hWinComm);
  1012. }
  1013. pstPrivate->hWinComm = INVALID_HANDLE_VALUE;
  1014. return iRetVal;
  1015. }
  1016. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  1017. * FUNCTION: PortConfigure
  1018. *
  1019. * DESCRIPTION:
  1020. * Configures an open port with the current set of user settings
  1021. *
  1022. * ARGUMENTS:
  1023. * pstPrivate -- The driver data structure
  1024. *
  1025. * RETURNS:
  1026. * COM_OK if port is configured successfully
  1027. * COM_DEVICE_ERROR if API errors are encountered
  1028. * COM_DEVICE_INVALID_SETTING if some user settings are not valid
  1029. */
  1030. int WINAPI PortConfigure(ST_STDCOM *pstPrivate)
  1031. {
  1032. int iRetVal = COM_OK;
  1033. unsigned uOverrides = 0;
  1034. DWORD dwError;
  1035. DWORD dwStructSize;
  1036. DCB *pstDcb;
  1037. COMMCONFIG stCommConfig;
  1038. COMMTIMEOUTS stCT;
  1039. dwStructSize = sizeof(stCommConfig);
  1040. stCommConfig.dwSize = sizeof(stCommConfig);
  1041. if (!GetCommConfig(pstPrivate->hWinComm, &stCommConfig, &dwStructSize))
  1042. {
  1043. //* DeviceReportError(pstPrivate, SID_ERR_WINDRIVER, 0, TRUE);
  1044. iRetVal = COM_DEVICE_ERROR;
  1045. }
  1046. else
  1047. {
  1048. pstDcb = &stCommConfig.dcb;
  1049. ComstdSettingsToDCB(&pstPrivate->stWorkSettings, pstDcb);
  1050. // Check for overrides
  1051. ComQueryOverride(pstPrivate->hCom, &uOverrides);
  1052. if (bittest(uOverrides, COM_OVERRIDE_8BIT))
  1053. {
  1054. pstDcb->ByteSize = 8;
  1055. pstDcb->Parity = NOPARITY;
  1056. }
  1057. // If we need to receive all 256 chars., we need to override
  1058. // XON/XOFF during sending since it will strip XON & XOFF from
  1059. // the incoming stream if enabled
  1060. if (bittest(uOverrides, COM_OVERRIDE_RCVALL))
  1061. pstDcb->fOutX = 0;
  1062. stCommConfig.dwSize = sizeof(stCommConfig);
  1063. if (!SetCommConfig(pstPrivate->hWinComm, &stCommConfig,
  1064. dwStructSize))
  1065. {
  1066. dwError = GetLastError();
  1067. //* Use GetLastError to figure out what went wrong, but
  1068. //* docs don't specify which error to check for.
  1069. // At this point SOME setting in the DCB is bad but there is
  1070. // no way to find out which. Since the baud rate is a likely
  1071. // candidate. Try reissuing the command with a common baud
  1072. // rate to see if the problem goes away
  1073. //
  1074. pstDcb->BaudRate = 1200;
  1075. if (!SetCommConfig(pstPrivate->hWinComm, &stCommConfig,
  1076. sizeof(stCommConfig)))
  1077. {
  1078. // If its still no good them some other setting is bad
  1079. //* DeviceReportError(pstPrivate, SID_ERR_BADSETTING, 0, TRUE);
  1080. }
  1081. else
  1082. {
  1083. // Changing baud rate to 1200 worked, so the user's baud
  1084. // rate must be what the driver is refusing
  1085. //* DeviceReportError(pstPrivate, SID_ERR_BADBAUD, 0, TRUE);
  1086. }
  1087. iRetVal = COM_DEVICE_INVALID_SETTING;
  1088. }
  1089. else
  1090. {
  1091. stCT.ReadIntervalTimeout = 10;
  1092. stCT.ReadTotalTimeoutMultiplier = 0;
  1093. stCT.ReadTotalTimeoutConstant = 0;
  1094. stCT.WriteTotalTimeoutMultiplier = 0;
  1095. stCT.WriteTotalTimeoutConstant = 5000;
  1096. if (!SetCommTimeouts(pstPrivate->hWinComm, &stCT))
  1097. {
  1098. assert(FALSE);
  1099. iRetVal = COM_DEVICE_INVALID_SETTING;
  1100. }
  1101. }
  1102. }
  1103. return iRetVal;
  1104. }
  1105. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  1106. * FUNCTION:
  1107. * PortExtactSettings
  1108. *
  1109. * DESCRIPTION:
  1110. * Extracts current Com settings from the Windows Com driver. This is
  1111. * needed when we are passed an existing Com handle by something like TAPI
  1112. *
  1113. * ARGUMENTS:
  1114. * pstPrivate -- The driver data structure
  1115. *
  1116. * RETURNS:
  1117. * COM_OK if port is configured successfully
  1118. * COM_DEVICE_ERROR if API errors are encountered
  1119. */
  1120. int PortExtractSettings(ST_STDCOM *pstPrivate)
  1121. {
  1122. int iRetVal;
  1123. DWORD dwError;
  1124. DWORD dwSize;
  1125. COMMCONFIG stCommConfig;
  1126. dwSize = sizeof(stCommConfig);
  1127. if (!GetCommConfig(pstPrivate->hWinComm, &stCommConfig, &dwSize))
  1128. {
  1129. dwError = GetLastError();
  1130. //* DeviceReportError(pstPrivate, SID_ERR_WINDRIVER, 0, TRUE);
  1131. iRetVal = COM_DEVICE_ERROR;
  1132. }
  1133. else
  1134. {
  1135. // Unload appropriate values from DCB to our settings structure
  1136. ComstdDCBToSettings(&stCommConfig.dcb, &pstPrivate->stWorkSettings);
  1137. // Don't leave autodetect on if user has already set something
  1138. // other than 8N1
  1139. DBG_AD("DBG_AD: fAutoDetect = %d\r\n",
  1140. pstPrivate->stWorkSettings.fAutoDetect, 0,0,0,0);
  1141. if (pstPrivate->stWorkSettings.fAutoDetect)
  1142. {
  1143. if (pstPrivate->stWorkSettings.nDataBits != 8 ||
  1144. pstPrivate->stWorkSettings.nParity != NOPARITY ||
  1145. pstPrivate->stWorkSettings.nStopBits != ONESTOPBIT)
  1146. {
  1147. DBG_AD("DBG_AD: Turning fAutoDetect off due to non 8N1\r\n",
  1148. 0,0,0,0,0);
  1149. pstPrivate->stWorkSettings.fAutoDetect = FALSE;
  1150. }
  1151. }
  1152. iRetVal = COM_OK;
  1153. }
  1154. return iRetVal;
  1155. }
  1156. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  1157. * FUNCTION:
  1158. * PortDefaultSettings
  1159. *
  1160. * DESCRIPTION:
  1161. * Extracts current Com settings from the Windows Com driver. This is
  1162. * needed when we are passed an existing Com handle by something like TAPI
  1163. *
  1164. * ARGUMENTS:
  1165. * pstPrivate -- The driver data structure
  1166. *
  1167. * RETURNS:
  1168. * COM_OK if port is configured successfully
  1169. * COM_DEVICE_ERROR if API errors are encountered
  1170. */
  1171. int PortDefaultSettings(ST_STDCOM *pstPrivate)
  1172. {
  1173. int iRetVal;
  1174. DWORD dwError;
  1175. COMMCONFIG stCommConfig;
  1176. DWORD dwSize = sizeof(stCommConfig);
  1177. TCHAR szPortName[COM_MAX_PORT_NAME];
  1178. if (pstPrivate == NULL || pstPrivate->hCom == NULL)
  1179. {
  1180. iRetVal = COM_INVALID_HANDLE;
  1181. }
  1182. else
  1183. {
  1184. ComGetPortName(pstPrivate->hCom, szPortName, COM_MAX_PORT_NAME);
  1185. if (StrCharGetStrLength(szPortName) == 0 || StrCharCmp(szPortName, "\0") == 0)
  1186. {
  1187. iRetVal = COM_DEVICE_ERROR;
  1188. }
  1189. else
  1190. {
  1191. if (!GetDefaultCommConfig(szPortName, &stCommConfig, &dwSize))
  1192. {
  1193. dwError = GetLastError();
  1194. //* DeviceReportError(pstPrivate, SID_ERR_WINDRIVER, 0, TRUE);
  1195. iRetVal = COM_DEVICE_ERROR;
  1196. }
  1197. else
  1198. {
  1199. // Unload appropriate values from DCB to our settings structure
  1200. ComstdDCBToSettings(&stCommConfig.dcb,
  1201. &pstPrivate->stWorkSettings);
  1202. // Don't leave autodetect on if user has already set something
  1203. // other than 8N1
  1204. DBG_AD("DBG_AD: fAutoDetect = %d\r\n",
  1205. pstPrivate->stWorkSettings.fAutoDetect, 0,0,0,0);
  1206. if (pstPrivate->stWorkSettings.fAutoDetect)
  1207. {
  1208. if (pstPrivate->stWorkSettings.nDataBits != 8 ||
  1209. pstPrivate->stWorkSettings.nParity != NOPARITY ||
  1210. pstPrivate->stWorkSettings.nStopBits != ONESTOPBIT)
  1211. {
  1212. DBG_AD("DBG_AD: Turning fAutoDetect off due to non 8N1\r\n",
  1213. 0,0,0,0,0);
  1214. pstPrivate->stWorkSettings.fAutoDetect = FALSE;
  1215. }
  1216. }
  1217. }
  1218. }
  1219. iRetVal = COM_OK;
  1220. }
  1221. return iRetVal;
  1222. }
  1223. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  1224. * FUNCTION: PortConnected
  1225. *
  1226. * DESCRIPTION:
  1227. * Determines whether the driver is currently connected to a host system.
  1228. * In the case of this driver, the presence of the carrier signal determines
  1229. * when we are connected.
  1230. *
  1231. * ARGUMENTS:
  1232. * pstPrivate -- Our private data structure
  1233. *
  1234. * RETURNS:
  1235. * TRUE if carrier is present
  1236. * FALSE if carrier is off
  1237. */
  1238. int WINAPI PortConnected(ST_STDCOM *pstPrivate)
  1239. {
  1240. int iRetVal = COM_PORT_NOT_OPEN;
  1241. DWORD dwModemStat;
  1242. if (GetCommModemStatus(pstPrivate->hWinComm, &dwModemStat))
  1243. {
  1244. if (bittest(dwModemStat, MS_RLSD_ON))
  1245. {
  1246. iRetVal = COM_PORT_OPEN;
  1247. }
  1248. }
  1249. if (iRetVal == COM_PORT_NOT_OPEN)
  1250. {
  1251. const HCOM hCom = pstPrivate->hCom;
  1252. if (hCom != NULL && ComValidHandle(hCom))
  1253. {
  1254. const HHCNCT hhCnct = (HHCNCT)sessQueryCnctHdl(hCom->hSession);
  1255. if (hhCnct != NULL)
  1256. {
  1257. const HHDRIVER hhDriver = (HHDRIVER)hhCnct->hDriver;
  1258. if (hhDriver != NULL)
  1259. {
  1260. if (!hhDriver->fCarrierDetect ||
  1261. bittest(hhDriver->stCallPar.dwBearerMode, LINEBEARERMODE_PASSTHROUGH))
  1262. {
  1263. iRetVal = COM_PORT_OPEN;
  1264. }
  1265. }
  1266. }
  1267. }
  1268. }
  1269. return iRetVal;
  1270. }
  1271. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  1272. * FUNCTION: RcvRefill
  1273. *
  1274. * DESCRIPTION:
  1275. * Called when the receive buffer is empty to refill it. This routine
  1276. * should attempt to refill the buffer and return the first character.
  1277. * It is important that this function be implemented efficiently.
  1278. *
  1279. * ARGUMENTS:
  1280. * pstPrivate -- the driver data structure
  1281. *
  1282. * RETURNS:
  1283. * TRUE if data is put in the receive buffer
  1284. * FALSE if there is no new incoming data
  1285. */
  1286. int WINAPI RcvRefill(ST_STDCOM *pstPrivate)
  1287. {
  1288. int fRetVal = FALSE;
  1289. ST_COM_CONTROL *pstComCntrl;
  1290. HCOM hCom;
  1291. EnterCriticalSection(&pstPrivate->csect);
  1292. pstPrivate->pbComStart = (pstPrivate->pbComEnd == pstPrivate->pbBufrEnd) ?
  1293. pstPrivate->pbBufrStart :
  1294. pstPrivate->pbComEnd;
  1295. pstPrivate->pbComEnd = (pstPrivate->pbReadEnd >= pstPrivate->pbComStart) ?
  1296. pstPrivate->pbReadEnd :
  1297. pstPrivate->pbBufrEnd;
  1298. DBG_READ("DBG_READ: Refill ComStart==%x, ComEnd==%x (ReadEnd==%x)\r\n",
  1299. pstPrivate->pbComStart, pstPrivate->pbComEnd,
  1300. pstPrivate->pbReadEnd, 0,0);
  1301. if (pstPrivate->fBufrFull)
  1302. {
  1303. DBG_READ("DBG_READ: Refill Signalling EVENT_READ\r\n", 0,0,0,0,0);
  1304. SetEvent(pstPrivate->ahEvent[EVENT_READ]);
  1305. }
  1306. if (pstPrivate->pbComStart == pstPrivate->pbComEnd)
  1307. {
  1308. DBG_READ("DBG_READ: Refill setting fBufrEmpty = TRUE\r\n", 0,0,0,0,0);
  1309. pstPrivate->fBufrEmpty = TRUE;
  1310. hCom = pstPrivate->hCom;
  1311. LeaveCriticalSection(&pstPrivate->csect);
  1312. ComNotify(hCom, NODATA);
  1313. EnterCriticalSection(&pstPrivate->csect);
  1314. }
  1315. else
  1316. {
  1317. pstComCntrl = (ST_COM_CONTROL *)pstPrivate->hCom;
  1318. pstComCntrl->puchRBData = pstPrivate->pbComStart;
  1319. pstComCntrl->puchRBDataLimit = pstPrivate->pbComEnd;
  1320. #if defined(DEBUG_CHARDUMP)
  1321. {
  1322. int iAvail;
  1323. int iCnt;
  1324. iAvail = (int) pstComCntrl->puchRBDataLimit - pstComCntrl->puchRBData;
  1325. fprintf(pfDbgC,
  1326. "Consumed -- %d bytes 0x%p to 0x%p:",
  1327. iAvail,
  1328. pstComCntrl->puchRBData,
  1329. pstComCntrl->puchRBDataLimit - 1);
  1330. for (iCnt = 0; iCnt < iAvail; ++iCnt)
  1331. {
  1332. if ((iCnt % 16) == 0)
  1333. fputs("\n", pfDbgC);
  1334. fprintf(pfDbgC, "%02X ", pstComCntrl->puchRBData[iCnt]);
  1335. }
  1336. fputs("\n", pfDbgC);
  1337. }
  1338. #endif
  1339. // If this com driver were being used to make the connection, we
  1340. // would have to check here to see whether we were connected before
  1341. // we called AutoDetect. Since TAPI takes care of making the
  1342. // connection for this app, we can just start auto detecting
  1343. // whenever we get control
  1344. if (pstPrivate->stWorkSettings.fAutoDetect)
  1345. {
  1346. AutoDetectAnalyze(pstPrivate,
  1347. (int)(pstPrivate->pbComEnd - pstPrivate->pbComStart),
  1348. pstPrivate->pbComStart);
  1349. }
  1350. fRetVal = TRUE;
  1351. }
  1352. LeaveCriticalSection(&pstPrivate->csect);
  1353. return fRetVal;
  1354. }
  1355. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  1356. * FUNCTION: RcvClear
  1357. *
  1358. * DESCRIPTION:
  1359. * Clears the receiver of all received data.
  1360. *
  1361. * ARGUMENTS:
  1362. * hCom -- a comm handle returned by an earlier call to ComCreateHandle
  1363. *
  1364. * RETURNS:
  1365. * COM_OK if data is cleared
  1366. * COM_DEVICE_ERROR if Windows com device driver returns an error
  1367. */
  1368. int WINAPI RcvClear(ST_STDCOM *pstPrivate)
  1369. {
  1370. int iRetVal = COM_OK;
  1371. ST_COM_CONTROL *pstComCntrl;
  1372. EnterCriticalSection(&pstPrivate->csect);
  1373. pstComCntrl = (ST_COM_CONTROL *)pstPrivate->hCom;
  1374. // Set buffer pointers to clear out any data we might have queued
  1375. pstComCntrl->puchRBData = pstPrivate->pbBufrStart;
  1376. pstComCntrl->puchRBDataLimit = pstPrivate->pbBufrStart;
  1377. pstPrivate->pbReadEnd = pstPrivate->pbBufrStart;
  1378. pstPrivate->pbComStart = pstPrivate->pbBufrStart;
  1379. pstPrivate->pbComEnd = pstPrivate->pbBufrStart;
  1380. if (!PurgeComm(pstPrivate->hWinComm, PURGE_RXCLEAR | PURGE_RXABORT))
  1381. iRetVal = COM_DEVICE_ERROR;
  1382. LeaveCriticalSection(&pstPrivate->csect);
  1383. return iRetVal;
  1384. }
  1385. // Buffered send routines
  1386. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  1387. * FUNCTION: SndBufrSend
  1388. *
  1389. * DESCRIPTION:
  1390. *
  1391. *
  1392. * ARGUMENTS:
  1393. *
  1394. *
  1395. * RETURNS:
  1396. *
  1397. */
  1398. int WINAPI SndBufrSend(ST_STDCOM *pstPrivate, void *pvBufr, int nSize)
  1399. {
  1400. int iRetVal = COM_OK;
  1401. DWORD dwBytesWritten;
  1402. DWORD dwError;
  1403. HCOM hCom;
  1404. assert(pvBufr != (void *)0);
  1405. assert(nSize <= SIZE_OUTQ);
  1406. if (nSize > 0)
  1407. {
  1408. EnterCriticalSection(&pstPrivate->csect);
  1409. // If Auto Detection is on, we may need to manually alter the
  1410. // parity of the output
  1411. if (pstPrivate->stWorkSettings.fAutoDetect)
  1412. {
  1413. AutoDetectOutput(pstPrivate, pvBufr, nSize);
  1414. }
  1415. hCom = pstPrivate->hCom;
  1416. LeaveCriticalSection(&pstPrivate->csect);
  1417. ComNotify(hCom, SEND_STARTED);
  1418. #if defined(DEADWOOD)
  1419. // We had a bug that caused the session to stop displaying new characters when
  1420. // you used auto-connect to start typing to a modem on Win 95. I tracked it down
  1421. // to this point in the code by moving a debug trace statement around. Put it
  1422. // just before this EnterCriticalSection and the bug goes away. Put it just after
  1423. // and the bug comes back. I discovered that replacing the DbgOutStr with a Sleep(0)
  1424. // had the same effect. This is a cheap fix but seems to work. We may want to
  1425. // spend the time to figure out exactly what is going on sometime in the future.
  1426. //jkh 9/9/98
  1427. Sleep(0);
  1428. //
  1429. // JohnFu 2/13/02, the EnterCriticalSection was just below this Sleep(0) now
  1430. // moved to top of the if statement. It was possible for other threads to
  1431. // modify the members of pstPrivate anytime between the above three statements.
  1432. // That may be the original cause of the bug described above. The reason the Sleep(0)
  1433. // fixed that bug further proves that possibility. There should be no need to
  1434. // place the Sleep here any longer.
  1435. // I added the sleep back in to see if the file transfer issues we
  1436. // were seeing with large file transfers would be corrected by adding
  1437. // the sleep back in. REV: 4/8/2002
  1438. //
  1439. // Made this Sleep(0) as deadwood since this may cause the deadlock
  1440. // to reappear. This did not correct the large file transfer problem
  1441. // we were seeing. REV: 7/11/2002
  1442. //
  1443. #endif // defined(DEADWOOD)
  1444. EnterCriticalSection(&pstPrivate->csect);
  1445. assert(pstPrivate->dwBytesToSend == 0);
  1446. assert(pstPrivate->dwSndOffset == 0);
  1447. assert((pstPrivate->dwSndOffset + nSize) <= SIZE_OUTQ);
  1448. #if defined(TODO)
  1449. //
  1450. // TODO:REV 7/11/2002 this is where the Ymodem-G is having problems and we are
  1451. // getting retries in file transfers. When the pstPrivate->dwBytesToSend is != 0,
  1452. // or the pstPrivate->dwSndOffset != 0, then we are overwriting the character
  1453. // that is existing in the buffer. We need to make sure we don't overwrite the
  1454. // buffer and/or clobber existing data in the buffer.
  1455. //
  1456. MemCopy(&pstPrivate->pbSndBufr[pstPrivate->dwSndOffset], (BYTE*) pvBufr, nSize);
  1457. pstPrivate->dwBytesToSend += nSize;
  1458. //pstPrivate->dwSndOffset = 0;
  1459. #else // defined(TODO)
  1460. MemCopy(pstPrivate->pbSndBufr, (BYTE*) pvBufr, nSize);
  1461. pstPrivate->dwBytesToSend = nSize;
  1462. pstPrivate->dwSndOffset = 0;
  1463. #endif // defined(TODO)
  1464. pstPrivate->stWriteOv.Offset = pstPrivate->stWriteOv.OffsetHigh = 0;
  1465. pstPrivate->stWriteOv.hEvent = pstPrivate->ahEvent[EVENT_WRITE];
  1466. DBG_WRITE("DBG_WRITE: %d WriteFile nSize==%d 0x%x\r\n", GetTickCount(),nSize,pstPrivate->hWinComm,0,0);
  1467. // jmh:01-12-96 When the OVERLAPPED structure is passed to WriteFile,
  1468. // there is character loss. Thorough investigation indicates a problem
  1469. // within Win32 comm. Documentation says behavior is undefined when
  1470. // this structure is not passed, but it works.
  1471. if (WriteFile(pstPrivate->hWinComm, pstPrivate->pbSndBufr, (DWORD)nSize,
  1472. &dwBytesWritten, &pstPrivate->stWriteOv)) // mrw:12/6/95 restored stWriteOv
  1473. {
  1474. assert(dwBytesWritten == (DWORD)nSize);
  1475. DBG_WRITE("DBG_WRITE: %d WriteFile completed synchronously\r\n",GetTickCount(),0,0,0,0);
  1476. hCom = pstPrivate->hCom;
  1477. LeaveCriticalSection(&pstPrivate->csect);
  1478. ComNotify(hCom, SEND_DONE);
  1479. EnterCriticalSection(&pstPrivate->csect);
  1480. pstPrivate->dwBytesToSend = 0;
  1481. }
  1482. else
  1483. {
  1484. dwError = GetLastError();
  1485. if (dwError == ERROR_IO_PENDING)
  1486. {
  1487. pstPrivate->fSending = TRUE;
  1488. }
  1489. else
  1490. {
  1491. iRetVal = COM_FAILED;
  1492. DBG_WRITE("DBG_WRITE: %d WriteFile failed %d 0x%x\r\n", GetTickCount(),dwError,pstPrivate->hWinComm,0,0);
  1493. }
  1494. }
  1495. LeaveCriticalSection(&pstPrivate->csect);
  1496. }
  1497. return iRetVal;
  1498. }
  1499. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  1500. * FUNCTION: SndBufrIsBusy
  1501. *
  1502. * DESCRIPTION:
  1503. * Determines whether the driver is available to transmit a buffer of
  1504. * data or not.
  1505. *
  1506. * ARGUMENTS:
  1507. * pstPrivate -- address of com driver's data structure
  1508. *
  1509. * RETURNS:
  1510. * COM_OK if data can be transmitted
  1511. * COM_BUSY if driver is still working on a previous buffer
  1512. */
  1513. int WINAPI SndBufrIsBusy(ST_STDCOM *pstPrivate)
  1514. {
  1515. int iRetVal = COM_OK;
  1516. EnterCriticalSection(&pstPrivate->csect);
  1517. if (pstPrivate->fBreakSignalOn || pstPrivate->fSending)
  1518. {
  1519. iRetVal = COM_BUSY;
  1520. }
  1521. LeaveCriticalSection(&pstPrivate->csect);
  1522. return iRetVal;
  1523. }
  1524. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  1525. * FUNCTION: SndBufrQuery
  1526. *
  1527. * DESCRIPTION:
  1528. *
  1529. *
  1530. * ARGUMENTS:
  1531. *
  1532. *
  1533. * RETURNS:
  1534. *
  1535. */
  1536. int WINAPI SndBufrQuery(ST_STDCOM *pstPrivate,
  1537. unsigned *pafStatus,
  1538. long *plHandshakeDelay)
  1539. {
  1540. int iRetVal = COM_OK;
  1541. DWORD dwErrors;
  1542. COMSTAT stComStat;
  1543. assert(pafStatus != NULL);
  1544. *pafStatus = 0;
  1545. //* temporary
  1546. if (!SndBufrIsBusy(pstPrivate))
  1547. {
  1548. // If no send is in progress, return clear status
  1549. *pafStatus = 0;
  1550. if (plHandshakeDelay)
  1551. *plHandshakeDelay = 0L;
  1552. }
  1553. else
  1554. {
  1555. if (ClearCommError(pstPrivate->hWinComm, &dwErrors, &stComStat))
  1556. {
  1557. if (stComStat.fXoffHold)
  1558. bitset(*pafStatus, COMSB_WAIT_XON);
  1559. if (stComStat.fCtsHold)
  1560. bitset(*pafStatus, COMSB_WAIT_CTS);
  1561. if (stComStat.fDsrHold)
  1562. bitset(*pafStatus, COMSB_WAIT_DSR);
  1563. if (stComStat.fRlsdHold)
  1564. bitset(*pafStatus, COMSB_WAIT_DCD);
  1565. if (stComStat.fXoffSent)
  1566. bitset(*pafStatus, COMSB_WAIT_BUSY);
  1567. if (*pafStatus && pstPrivate->lSndStuck == -1L)
  1568. pstPrivate->lSndStuck = (long)startinterval();
  1569. if (plHandshakeDelay)
  1570. *plHandshakeDelay =
  1571. (pstPrivate->lSndStuck == -1L ?
  1572. 0L : (long)interval(pstPrivate->lSndStuck));
  1573. }
  1574. }
  1575. return iRetVal;
  1576. }
  1577. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  1578. * FUNCTION: SndBufrClear
  1579. *
  1580. * DESCRIPTION:
  1581. *
  1582. *
  1583. * ARGUMENTS:
  1584. *
  1585. *
  1586. * RETURNS:
  1587. *
  1588. */
  1589. int WINAPI SndBufrClear(ST_STDCOM *pstPrivate)
  1590. {
  1591. int iRetVal = COM_OK;
  1592. EnterCriticalSection(&pstPrivate->csect);
  1593. if (SndBufrIsBusy(pstPrivate))
  1594. {
  1595. if (!PurgeComm(pstPrivate->hWinComm, PURGE_TXCLEAR | PURGE_TXABORT))
  1596. iRetVal = COM_DEVICE_ERROR;
  1597. }
  1598. LeaveCriticalSection(&pstPrivate->csect);
  1599. return iRetVal;
  1600. }
  1601. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  1602. * FUNCTION: ComstdThread
  1603. *
  1604. * DESCRIPTION:
  1605. * This thread services three events, reads, writes and rithmatic, uh
  1606. * no, I mean comm events. It uses overlapped I/O to accomplish this
  1607. * task which simplifies the task since thread contention between the
  1608. * different events is eliminated.
  1609. *
  1610. * ARGUMENTS:
  1611. * pvData - pointer to private comm handle
  1612. *
  1613. * RETURNS:
  1614. * Eventually
  1615. *
  1616. */
  1617. DWORD WINAPI ComstdThread(void *pvData)
  1618. {
  1619. ST_STDCOM *pstPrivate = (ST_STDCOM *)pvData;
  1620. DWORD dwResult = WAIT_OBJECT_0;
  1621. DWORD dwError;
  1622. DWORD dwBytes;
  1623. DWORD dwComEvent = 0;
  1624. long lBytesRead;
  1625. long lReadSize;
  1626. BYTE *pbReadFrom;
  1627. OVERLAPPED stReadOv;
  1628. OVERLAPPED stEventOv;
  1629. COMSTAT stComStat;
  1630. HANDLE *pEvents;
  1631. HCOM hCom;
  1632. #if defined(DEBUG_CHARDUMP)
  1633. int iCnt;
  1634. #endif
  1635. DWORD dwEvents;
  1636. DBG_THREAD("DBG_THREAD: ComstdThread starting\r\n",0,0,0,0,0);
  1637. EnterCriticalSection(&pstPrivate->csect);
  1638. // Set Read event to signaled to get the first Read operation going
  1639. //
  1640. pstPrivate->fBufrFull = TRUE;
  1641. SetEvent(pstPrivate->ahEvent[EVENT_READ]);
  1642. // Set ComEvent event to signaled to to get the first WaitCommEvent
  1643. // started
  1644. //
  1645. SetEvent(pstPrivate->ahEvent[EVENT_COMEVENT]);
  1646. // Clear any set state left by a previous connection.
  1647. //
  1648. ResetEvent(pstPrivate->ahEvent[EVENT_WRITE]);
  1649. for ( ; ; )
  1650. {
  1651. dwEvents = DIM(pstPrivate->ahEvent);
  1652. pEvents = pstPrivate->ahEvent;
  1653. LeaveCriticalSection(&pstPrivate->csect);
  1654. DBG_THREAD("DBG_THREAD: Waiting\r\n", 0,0,0,0,0);
  1655. dwResult = WaitForMultipleObjects(dwEvents, pEvents,
  1656. FALSE, INFINITE);
  1657. DBG_THREAD("DBG_THREAD: WaitForMultipleObjects returned %d\r\n",
  1658. dwResult,0,0,0,0);
  1659. EnterCriticalSection(&pstPrivate->csect);
  1660. // To get this thread to exit, the deactivate routine forces a
  1661. // fake com event by calling SetCommMask
  1662. //
  1663. if (pstPrivate->fHaltThread)
  1664. {
  1665. LeaveCriticalSection(&pstPrivate->csect);
  1666. DBG_THREAD("DBG_THREAD: ComStd exiting thread\r\n",0,0,0,0,0);
  1667. ExitThread(0);
  1668. }
  1669. switch (dwResult)
  1670. {
  1671. case WAIT_OBJECT_0 + EVENT_READ:
  1672. if (pstPrivate->fBufrFull)
  1673. {
  1674. DBG_READ("DBG_READ: Thread -- fBufrFull = FALSE\r\n",
  1675. 0,0,0,0,0);
  1676. pstPrivate->fBufrFull = FALSE;
  1677. }
  1678. else
  1679. {
  1680. if (GetOverlappedResult(pstPrivate->hWinComm, &stReadOv,
  1681. (DWORD *)&lBytesRead, FALSE))
  1682. {
  1683. pstPrivate->pbReadEnd += lBytesRead;
  1684. #if defined(DEBUG_CHARDUMP)
  1685. if (lBytesRead > 0)
  1686. {
  1687. fprintf(pfDbgR,
  1688. "Overlapped Read -- %d bytes 0x%p to 0x%p:",
  1689. lBytesRead, pbReadFrom,
  1690. pstPrivate->pbReadEnd - 1);
  1691. for (iCnt = 0; iCnt < lBytesRead; ++iCnt)
  1692. {
  1693. if ((iCnt % 16) == 0)
  1694. fputs("\n", pfDbgR);
  1695. fprintf(pfDbgR, "%02X ", pbReadFrom[iCnt]);
  1696. }
  1697. fputs("\n", pfDbgR);
  1698. }
  1699. #endif
  1700. if (pstPrivate->pbReadEnd >= pstPrivate->pbBufrEnd)
  1701. {
  1702. pstPrivate->pbReadEnd = pstPrivate->pbBufrStart;
  1703. }
  1704. DBG_READ("DBG_READ: Thread -- got %ld, ReadEnd==%x\r\n",
  1705. lBytesRead, pstPrivate->pbReadEnd,0,0,0);
  1706. if (pstPrivate->fBufrEmpty)
  1707. {
  1708. DBG_READ("DBG_READ: Thread -- fBufrEmpty = FALSE\r\n",
  1709. 0,0,0,0,0);
  1710. pstPrivate->fBufrEmpty = FALSE;
  1711. hCom = pstPrivate->hCom;
  1712. LeaveCriticalSection(&pstPrivate->csect);
  1713. ComNotify(hCom, DATA_RECEIVED);
  1714. EnterCriticalSection(&pstPrivate->csect);
  1715. }
  1716. }
  1717. else
  1718. {
  1719. switch (GetLastError())
  1720. {
  1721. case ERROR_OPERATION_ABORTED:
  1722. // Operations can be aborted by calls to PurgeComm()
  1723. // Allow setup for another read request.
  1724. // mrw:12/14/95
  1725. //
  1726. break;
  1727. default:
  1728. // Com is failing for some reason. Exit thread
  1729. // so that we don't tie-up resources.
  1730. //
  1731. DBG_EVENTS("DBG_EVENTS: GetOverlappedResult "
  1732. "failed!\r\n",0,0,0,0,0);
  1733. LeaveCriticalSection(&pstPrivate->csect);
  1734. ExitThread(0);
  1735. }
  1736. }
  1737. }
  1738. // Do reads until we fill the buffer or we get an overlapped read
  1739. //
  1740. for ( ; ; )
  1741. {
  1742. // Check for wrap around in circular buffer
  1743. //
  1744. pbReadFrom = (pstPrivate->pbReadEnd >= pstPrivate->pbBufrEnd) ?
  1745. pstPrivate->pbBufrStart :
  1746. pstPrivate->pbReadEnd;
  1747. #if 0 // mrw:10/7/96 - enabled shiva fix for NT 4.0 Service Pack
  1748. // Enabled for NT 4.0 release. Per Microsoft, leave this bug
  1749. // in, so US and international versions are identical. It was
  1750. // found between US and international releases.
  1751. //
  1752. // This was causing bad packets in Zmodem transfers when
  1753. // using Shiva's LanRover, which appeared at baud rates
  1754. // of 57600 or higher, and using TCP/IP to connect to the
  1755. // LanRover. lReadSize in this code would not leave an
  1756. // unused byte at the end of the buffer if pbComStart was
  1757. // pointing to the beginning of the buffer.
  1758. // - jmh 07-31-96
  1759. lReadSize = (pbReadFrom < pstPrivate->pbComStart) ?
  1760. (pstPrivate->pbComStart - pbReadFrom - 1) :
  1761. (pstPrivate->pbBufrEnd - pbReadFrom);
  1762. #else
  1763. // Determine the extent to which we're allowed to fill the
  1764. // buffer. pbComStart points to the start of where the buffer
  1765. // is "reserved", waiting to be emptied from. We make sure we
  1766. // leave the byte before pbComStart empty. - jmh 07-31-96
  1767. //
  1768. if (pbReadFrom < pstPrivate->pbComStart)
  1769. {
  1770. lReadSize = (long)(pstPrivate->pbComStart - pbReadFrom - 1);
  1771. }
  1772. else
  1773. {
  1774. lReadSize = (long)(pstPrivate->pbBufrEnd - pbReadFrom);
  1775. // The circular buffer code was written so that the address
  1776. // pointed to by pbBufrEnd is equated with pbBufrStart. We
  1777. // also need to make sure that if we've just calculated
  1778. // that we can read to the end of the buffer (aka the
  1779. // *start* of the buffer), and pbComStart is pointing to
  1780. // the start of the buffer, there's still an empty byte
  1781. // before pbComStart. - jmh 07-31-96
  1782. //
  1783. if (pstPrivate->pbComStart == pstPrivate->pbBufrStart)
  1784. lReadSize -= 1;
  1785. }
  1786. #endif
  1787. if (lReadSize > MAX_READSIZE)
  1788. {
  1789. lReadSize = MAX_READSIZE;
  1790. }
  1791. if (lReadSize == 0)
  1792. {
  1793. DBG_READ("DBG_READ: Thread -- fBufrFull = TRUE, "
  1794. "unsignalling EVENT_READ\r\n",0,0,0,0,0);
  1795. pstPrivate->fBufrFull = TRUE;
  1796. ResetEvent(pstPrivate->ahEvent[EVENT_READ]);
  1797. break;
  1798. }
  1799. else
  1800. {
  1801. // Set up to do an overlapped read. From what I can make
  1802. // of the documenation, this may or may not complete
  1803. // immediately. So, to be safe, I will code it to expect
  1804. // either result.
  1805. //
  1806. stReadOv.Offset = stReadOv.OffsetHigh = 0;
  1807. stReadOv.hEvent = pstPrivate->ahEvent[EVENT_READ];
  1808. DBG_READ("DBG_READ: Thread -- ReadFile started, "
  1809. "ReadFrom==%x, ReadSize==%ld\r\n",
  1810. pbReadFrom, lReadSize, 0,0,0);
  1811. // ReadFile resets the read event semaphore
  1812. //
  1813. if (ReadFile(pstPrivate->hWinComm, pbReadFrom,
  1814. (DWORD)lReadSize, (DWORD *)&lBytesRead,
  1815. &stReadOv))
  1816. {
  1817. pstPrivate->pbReadEnd += lBytesRead;
  1818. #if defined(DEBUG_CHARDUMP)
  1819. fprintf(pfDbgR,
  1820. "Overlapped Read -- %d bytes 0x%p to 0x%p:",
  1821. lBytesRead, pbReadFrom,
  1822. pstPrivate->pbReadEnd - 1);
  1823. for (iCnt = 0; iCnt < lBytesRead; ++iCnt)
  1824. {
  1825. if ((iCnt % 16) == 0)
  1826. fputs("\n", pfDbgR);
  1827. fprintf(pfDbgR, "%02X ", pbReadFrom[iCnt]);
  1828. }
  1829. fputs("\n", pfDbgR);
  1830. #endif
  1831. if (pstPrivate->pbReadEnd >= pstPrivate->pbBufrEnd)
  1832. pstPrivate->pbReadEnd = pstPrivate->pbBufrStart;
  1833. DBG_READ("DBG_READ: Thread -- ReadFile completed "
  1834. "synchronously, lBytesRead==%ld, ReadEnd==%x\r\n",
  1835. lBytesRead, pstPrivate->pbReadEnd,0,0,0);
  1836. if (pstPrivate->fBufrEmpty)
  1837. {
  1838. DBG_READ("DBG_READ: Thread -- fBufrEmpty = "
  1839. "FALSE\r\n", 0,0,0,0,0);
  1840. pstPrivate->fBufrEmpty = FALSE;
  1841. hCom = pstPrivate->hCom;
  1842. LeaveCriticalSection(&pstPrivate->csect);
  1843. ComNotify(hCom, DATA_RECEIVED);
  1844. EnterCriticalSection(&pstPrivate->csect);
  1845. }
  1846. }
  1847. else
  1848. {
  1849. switch (GetLastError())
  1850. {
  1851. case ERROR_IO_PENDING:
  1852. break;
  1853. case ERROR_OPERATION_ABORTED:
  1854. // PurgeComm can do this. Setup for another read.
  1855. // mrw:12/14/95
  1856. // But clear errors or the read may fail from
  1857. // now to eternity! We're in an infinite for-loop,
  1858. // after all. jmh:06-12-96
  1859. ClearCommError(pstPrivate->hWinComm, &dwError, &stComStat);
  1860. continue;
  1861. default:
  1862. // Com is failing for some reason. Exit thread
  1863. // so that we don't tie-up resources.
  1864. //
  1865. DBG_READ("DBG_READ: ReadFile failed!\r\n",
  1866. 0,0,0,0,0);
  1867. LeaveCriticalSection(&pstPrivate->csect);
  1868. ExitThread(0);
  1869. }
  1870. break; // Come back when event signals
  1871. }
  1872. }
  1873. }
  1874. break;
  1875. case WAIT_OBJECT_0 + EVENT_WRITE:
  1876. if (GetOverlappedResult(pstPrivate->hWinComm,
  1877. &pstPrivate->stWriteOv, &dwBytes, FALSE) == FALSE)
  1878. {
  1879. dwError = GetLastError();
  1880. DBG_WRITE("DBG_WRITE: %d Overlapped WriteFile failed: errno=%d\n",
  1881. GetTickCount(), dwError, 0, 0, 0);
  1882. }
  1883. else if (dwBytes < pstPrivate->dwBytesToSend && dwBytes != 0)
  1884. {
  1885. // ResetEvent(pstPrivate->ahEvent[EVENT_WRITE]);
  1886. DBG_WRITE("DBG_WRITE: %d Write result -- dwBytes==%d\r\n",
  1887. GetTickCount(),dwBytes,0,0,0);
  1888. // There's more to write. Seems kinda silly, but WriteFile
  1889. // will return a success code, and dwBytes will show
  1890. // there's still stuff to write. So we make another call
  1891. // to WriteFile for what's remaining. Perhaps the write
  1892. // timeout is too short. This happens for slower baud rates
  1893. //
  1894. pstPrivate->dwBytesToSend -= dwBytes;
  1895. pstPrivate->dwSndOffset += dwBytes;
  1896. pstPrivate->stWriteOv.Offset = pstPrivate->stWriteOv.OffsetHigh = 0;
  1897. pstPrivate->stWriteOv.hEvent = pstPrivate->ahEvent[EVENT_WRITE];
  1898. DBG_WRITE("DBG_WRITE: %d WriteFile(2) nSize==%d 0x%x\r\n",
  1899. GetTickCount(), pstPrivate->dwBytesToSend, pstPrivate->hWinComm, 0, 0);
  1900. if (WriteFile(pstPrivate->hWinComm,
  1901. &pstPrivate->pbSndBufr[pstPrivate->dwSndOffset],
  1902. pstPrivate->dwBytesToSend,
  1903. &dwBytes, &pstPrivate->stWriteOv))
  1904. {
  1905. assert(dwBytes == pstPrivate->dwBytesToSend);
  1906. DBG_WRITE("DBG_WRITE: %d WriteFile(2) completed synchronously\r\n", GetTickCount(),0,0,0,0);
  1907. }
  1908. else
  1909. {
  1910. dwError = GetLastError();
  1911. if (dwError == ERROR_IO_PENDING)
  1912. {
  1913. break; // This is what we expect
  1914. }
  1915. else
  1916. {
  1917. DBG_WRITE("DBG_WRITE: %d WriteFile(2) failed %d 0x%x\r\n", GetTickCount(),dwError,pstPrivate->hWinComm,0,0);
  1918. }
  1919. }
  1920. }
  1921. else
  1922. {
  1923. // The write semaphore must be reset after the call to
  1924. // GetOverlappedResult, because it checks the semaphore
  1925. // to see if there's an outstanding write call. jmh 01-10-96
  1926. //
  1927. ResetEvent(pstPrivate->ahEvent[EVENT_WRITE]);
  1928. }
  1929. DBG_WRITE("DBG_WRITE: %d Write result -- dwBytes==%d\r\n",
  1930. GetTickCount(),dwBytes,0,0,0);
  1931. pstPrivate->dwBytesToSend = 0;
  1932. pstPrivate->dwSndOffset = 0;
  1933. pstPrivate->fSending = FALSE;
  1934. hCom = pstPrivate->hCom;
  1935. LeaveCriticalSection(&pstPrivate->csect);
  1936. ComNotify(hCom, SEND_DONE);
  1937. EnterCriticalSection(&pstPrivate->csect);
  1938. break;
  1939. case WAIT_OBJECT_0 + EVENT_COMEVENT:
  1940. // WaitCommEvent is returning an event flag
  1941. //
  1942. ResetEvent(pstPrivate->ahEvent[EVENT_COMEVENT]);
  1943. switch (dwComEvent)
  1944. {
  1945. case EV_ERR:
  1946. ClearCommError(pstPrivate->hWinComm, &dwError, &stComStat);
  1947. DBG_EVENTS("DBG_EVENTS: EV_ERR dwError==%x\r\n",
  1948. dwError,0,0,0,0);
  1949. //* need code here to record errors, handle HHS stuck etc.
  1950. break;
  1951. case EV_RLSD: // receive-line-signal-detect changed state.
  1952. hCom = pstPrivate->hCom;
  1953. LeaveCriticalSection(&pstPrivate->csect);
  1954. ComNotify(hCom, CONNECT);
  1955. EnterCriticalSection(&pstPrivate->csect);
  1956. DBG_EVENTS("DBG_EVENTS: EV_RLSD\r\n", 0,0,0,0,0);
  1957. break;
  1958. default:
  1959. DBG_EVENTS("DBG_EVENTS: EV_??? (dwComEvent==%x)\r\n",
  1960. dwComEvent,0,0,0,0);
  1961. break;
  1962. }
  1963. // Start up another overlapped WaitCommEvent to get the
  1964. // next event
  1965. //
  1966. stEventOv.Offset = stEventOv.OffsetHigh = (DWORD)0;
  1967. stEventOv.hEvent = pstPrivate->ahEvent[EVENT_COMEVENT];
  1968. if (WaitCommEvent(pstPrivate->hWinComm, &dwComEvent, &stEventOv))
  1969. {
  1970. // Call completed synchronously, re-signal our event object
  1971. //
  1972. DBG_EVENTS("DBG_EVENTS: WaitCommEvent completed "
  1973. "synchronously\r\n",0,0,0,0,0);
  1974. SetEvent(pstPrivate->ahEvent[EVENT_COMEVENT]);
  1975. }
  1976. else
  1977. {
  1978. switch (GetLastError())
  1979. {
  1980. case ERROR_IO_PENDING:
  1981. break;
  1982. case ERROR_OPERATION_ABORTED:
  1983. // Not sure this can happen but we'll code it like
  1984. // the read. - mrw:12/14/95
  1985. //
  1986. DBG_EVENTS("DBG_EVENTS: WaitCommEvent - "
  1987. "ERROR_OPERATION_ABORTED\r\n",0,0,0,0,0);
  1988. SetEvent(pstPrivate->ahEvent[EVENT_COMEVENT]);
  1989. break;
  1990. default:
  1991. // Com is failing for some reason. Exit thread
  1992. // so that we don't tie-up resources.
  1993. //
  1994. DBG_EVENTS("DBG_EVENTS: WaitCommEvent failed!\r\n",
  1995. 0,0,0,0,0);
  1996. LeaveCriticalSection(&pstPrivate->csect);
  1997. ExitThread(0);
  1998. }
  1999. }
  2000. break;
  2001. default:
  2002. break;
  2003. }
  2004. }
  2005. LeaveCriticalSection(&pstPrivate->csect);
  2006. DBG_THREAD("DBG_THREAD: ComstdThread exiting\r\n",0,0,0,0,0);
  2007. return (DWORD)0;
  2008. }
  2009. /* --- AUTO DETECT ROUTINES --- */
  2010. static int Nibble[] = {0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0}; // 1=odd, 0=even
  2011. #define OddBits(b) (Nibble[(b) / 16] ^ Nibble[(b) % 16])
  2012. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  2013. * FUNCTION:
  2014. * AutoDetectAnalyze
  2015. *
  2016. * DESCRIPTION:
  2017. * Analyzes incoming data to determine the char size, parity type and
  2018. * stop bits
  2019. *
  2020. * ARGUMENTS:
  2021. *
  2022. *
  2023. * RETURNS:
  2024. *
  2025. */
  2026. void AutoDetectAnalyze(ST_STDCOM *pstPrivate, int nBytes, char *pchBufr)
  2027. {
  2028. char *pchScan = pchBufr;
  2029. char *pszMsg;
  2030. int fForceTo7Bits = FALSE;
  2031. int iCnt = nBytes;
  2032. if (!pstPrivate->fADRunning)
  2033. {
  2034. AutoDetectStart(pstPrivate);
  2035. // This was a temporary fix I used while debugging a 7E1 problem that I decided
  2036. // to leave in because it may help in some situations and shouldn't hurt.
  2037. // In my case, when a GVC Fax 11400 V.42bis/MNP5 modem was installed as
  2038. // "Standard Modem", an initial 8N1 CRLF from the modem negotiation got through
  2039. // even when connecting to a 7E1 host. This made auto detect decide the whole
  2040. // connection was 8N1. I fixed it with this little patch. Once I reinstalled the
  2041. // modem as itself, it worked without the patch. This is not a rigourous fix
  2042. // because there is no guarantee that there will be only two extraneous characters
  2043. // or that they will be read all by themselves -- but this will fix the problems
  2044. // in some typical cases and will do no harm. jkh 9/9/98
  2045. if (iCnt <= 2)
  2046. return;
  2047. }
  2048. if (pstPrivate->nFramingErrors > 0)
  2049. {
  2050. DBG_AD("DBG_AD: Got Framing Errors: shutting down\r\n", 0,0,0,0,0);
  2051. AutoDetectStop(pstPrivate);
  2052. // MessageBox(NULL,
  2053. // "Would use Wizard code here. Either wrong baud rate "
  2054. // "is set or unusual settings have been encountered. "
  2055. // "Finished code may be able to handle some cases included here.",
  2056. // "Auto Detection Wizard", MB_OK);
  2057. return;
  2058. }
  2059. pstPrivate->nADTotal += iCnt;
  2060. // for each byte, determine whether the lower 7 bits contain an odd
  2061. // number of 1 bits, then determine whether the byte would be a valid
  2062. // 7e1 character.
  2063. while (iCnt--)
  2064. {
  2065. if (OddBits(*pchScan & 0x7F))
  2066. ++pstPrivate->nADMix;
  2067. if (OddBits(*pchScan))
  2068. ++pstPrivate->nAD7o1;
  2069. if (*pchScan & 0x80)
  2070. ++pstPrivate->nADHighBits;
  2071. ++pchScan;
  2072. }
  2073. // See whether we can make any decision with what we've got
  2074. if (pstPrivate->nADMix > 0 && pstPrivate->nADMix < pstPrivate->nADTotal)
  2075. {
  2076. // We now have both kinds of characters: those with an even and
  2077. // an odd number of bits in the lower 7 bits - so we can make
  2078. // a guess.
  2079. if (pstPrivate->nAD7o1 == pstPrivate->nADTotal)
  2080. pstPrivate->nADBestGuess = AD_7O1;
  2081. else if (pstPrivate->nAD7o1 == 0)
  2082. pstPrivate->nADBestGuess = AD_7E1;
  2083. else
  2084. pstPrivate->nADBestGuess = AD_8N1;
  2085. }
  2086. DBG_AD("DBG_AD: Cnt=%3d, Mix=%3d, 7o1=%3d, HB=%3d BG=%d\r\n",
  2087. pstPrivate->nADTotal, pstPrivate->nADMix,
  2088. pstPrivate->nAD7o1, pstPrivate->nADHighBits,
  2089. pstPrivate->nADBestGuess);
  2090. // See whether we've checked a sufficient sample to determine settings
  2091. if (pstPrivate->nADBestGuess != AD_8N1 &&
  2092. (pstPrivate->nADTotal < MIN_AD_TOTAL ||
  2093. pstPrivate->nADMix < MIN_AD_MIX ||
  2094. (pstPrivate->nADTotal - pstPrivate->nADMix) < MIN_AD_MIX))
  2095. {
  2096. // Data sample is insufficient to draw a conclusion.
  2097. // For now, let the data display as 7-bit data and wait for more
  2098. fForceTo7Bits = TRUE;
  2099. }
  2100. else
  2101. {
  2102. // We have enough data to make a decision
  2103. if (pstPrivate->nAD7o1 == 0)
  2104. {
  2105. // Data is 7-even-1
  2106. pstPrivate->stWorkSettings.nDataBits = 7;
  2107. pstPrivate->stWorkSettings.nParity = EVENPARITY;
  2108. fForceTo7Bits = TRUE;
  2109. pstPrivate->fADReconfigure = TRUE;
  2110. pszMsg = "Establishing settings of 7-Even-1";
  2111. }
  2112. else if (pstPrivate->nAD7o1 == pstPrivate->nADTotal)
  2113. {
  2114. // Data is 7-odd-1
  2115. pstPrivate->stWorkSettings.nDataBits = 7;
  2116. pstPrivate->stWorkSettings.nParity = ODDPARITY;
  2117. fForceTo7Bits = TRUE;
  2118. pstPrivate->fADReconfigure = TRUE;
  2119. pszMsg = "Establishing settings of 7-Odd-1";
  2120. }
  2121. else
  2122. {
  2123. // Data is most likely 8-none-1. But if the high bit was
  2124. // set on all the received data, it may have been 7-mark-1 or
  2125. // some other odd setting
  2126. pstPrivate->stWorkSettings.nDataBits = 8;
  2127. pstPrivate->stWorkSettings.nParity = NOPARITY;
  2128. if (pstPrivate->nADHighBits == pstPrivate->nADTotal)
  2129. pszMsg = "Settings are either 8-none-1 or something quite "
  2130. "odd like 7-mark-one. A wizard would pop up here"
  2131. "asking the user if the data looked correct and"
  2132. "offering suggestions if it did not.";
  2133. else
  2134. pszMsg = "Establishing settings of 8-none-1";
  2135. }
  2136. // Decision has been made, so turn auto detect off
  2137. DBG_AD("DBG_AD: %s\r\n", pszMsg, 0,0,0,0);
  2138. AutoDetectStop(pstPrivate);
  2139. if (pstPrivate->fADReconfigure)
  2140. {
  2141. DBG_AD("DBG_AD: Reconfiguring port\r\n", 0,0,0,0,0);
  2142. PortConfigure(pstPrivate);
  2143. }
  2144. // MessageBox(NULL, pszMsg, "Auto Detection Done", MB_OK);
  2145. }
  2146. if (fForceTo7Bits)
  2147. {
  2148. while (nBytes--)
  2149. {
  2150. *pchBufr = (char)(*pchBufr & 0x7F);
  2151. ++pchBufr;
  2152. }
  2153. }
  2154. }
  2155. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  2156. * FUNCTION:
  2157. * AutoDetectOutput
  2158. *
  2159. * DESCRIPTION:
  2160. * Checks state of auto detection and alters outgoing characters to
  2161. * reflect the best guess of their parity status.
  2162. *
  2163. * ARGUMENTS:
  2164. *
  2165. *
  2166. * RETURNS:
  2167. *
  2168. */
  2169. void AutoDetectOutput(ST_STDCOM *pstPrivate, void *pvBufr, int nSize)
  2170. {
  2171. char *pch = (char *)pvBufr;
  2172. if (!pstPrivate->fADRunning)
  2173. AutoDetectStart(pstPrivate);
  2174. switch (pstPrivate->nADBestGuess)
  2175. {
  2176. case AD_8N1:
  2177. // Do nothing
  2178. break;
  2179. case AD_7E1:
  2180. // Make output look like 7e1
  2181. DBG_AD("DBG_AD: Converting %d output char(s) to 7E1\r\n",
  2182. nSize, 0,0,0,0);
  2183. while (nSize--)
  2184. {
  2185. if (OddBits(*pch & 0x7F))
  2186. *pch |= 0x80;
  2187. ++pch;
  2188. }
  2189. break;
  2190. case AD_7O1:
  2191. // Make output look like 7o1
  2192. DBG_AD("DBG_AD: Converting %d output char(s) to 7O1\r\n",
  2193. nSize, 0,0,0,0);
  2194. while (nSize--)
  2195. {
  2196. if (!OddBits(*pch & 0x7F))
  2197. *pch |= 0x80;
  2198. ++pch;
  2199. }
  2200. break;
  2201. case AD_DONT_KNOW:
  2202. // As long as the same single character is being sent
  2203. // out repeatedly, toggle the parity bit every other time
  2204. //
  2205. // This additional comment added. REV: 06/15/2001
  2206. //
  2207. // Some host systems that are 7-Even-1 or 7-Odd-1 require
  2208. // specific characters to be received in order to connect
  2209. // When HT is in AutoDetect mode, it is sending 8-None-1
  2210. // data, so the character that is sent will not be the
  2211. // character required to connect. In order to connect to
  2212. // the 7-Even-1 or 7-Odd-1 system, we must set the parity
  2213. // bit on the outbound character *pch = (*pch ^ (char)0x80);
  2214. // which will display a garbage character in HT. By setting
  2215. // the parity bit HT is now sending 7-Even-1 or 7-Odd-1 data
  2216. // depending on the character.
  2217. //
  2218. // An example is a 7E1 Genie systems require the user to
  2219. // enter <Ctrl>u or <Return> multiple times in order to
  2220. // connect.
  2221. //
  2222. if (nSize != 1)
  2223. {
  2224. pstPrivate->chADLastChar = '\0';
  2225. pstPrivate->fADToggleParity = FALSE;
  2226. }
  2227. else
  2228. {
  2229. if (*pch != pstPrivate->chADLastChar)
  2230. {
  2231. pstPrivate->chADLastChar = *pch;
  2232. pstPrivate->fADToggleParity = FALSE;
  2233. }
  2234. else
  2235. {
  2236. if (pstPrivate->fADToggleParity)
  2237. *pch = (*pch ^ (char)0x80);
  2238. pstPrivate->fADToggleParity = !pstPrivate->fADToggleParity;
  2239. }
  2240. }
  2241. break;
  2242. default:
  2243. assert(FALSE);
  2244. break;
  2245. }
  2246. }
  2247. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  2248. * FUNCTION:
  2249. * AutoDetectStart
  2250. *
  2251. * DESCRIPTION:
  2252. *
  2253. *
  2254. * ARGUMENTS:
  2255. *
  2256. *
  2257. * RETURNS:
  2258. *
  2259. */
  2260. void AutoDetectStart(ST_STDCOM *pstPrivate)
  2261. {
  2262. DBG_AD("DBG_AD: AutoDetectStart\r\n", 0,0,0,0,0);
  2263. pstPrivate->nADTotal = 0;
  2264. pstPrivate->nADMix = 0;
  2265. pstPrivate->nAD7o1 = 0;
  2266. pstPrivate->nADHighBits = 0;
  2267. pstPrivate->nADBestGuess = AD_DONT_KNOW;
  2268. pstPrivate->fADRunning = TRUE;
  2269. pstPrivate->chADLastChar = '\0';
  2270. pstPrivate->fADToggleParity = FALSE;
  2271. pstPrivate->fADReconfigure = FALSE;
  2272. pstPrivate->nFramingErrors = 0;
  2273. }
  2274. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  2275. * FUNCTION:
  2276. * AutoDetectStop
  2277. *
  2278. * DESCRIPTION:
  2279. *
  2280. *
  2281. * ARGUMENTS:
  2282. *
  2283. *
  2284. * RETURNS:
  2285. *
  2286. */
  2287. void AutoDetectStop(ST_STDCOM *pstPrivate)
  2288. {
  2289. HSESSION hSession;
  2290. DBG_AD("DBG_AD: AutoDetectStop\r\n", 0,0,0,0,0);
  2291. pstPrivate->stWorkSettings.fAutoDetect = FALSE;
  2292. pstPrivate->fADRunning = FALSE;
  2293. ComGetSession(pstPrivate->hCom, &hSession);
  2294. PostMessage(sessQueryHwndStatusbar(hSession),
  2295. SBR_NTFY_REFRESH, (WPARAM)SBR_COM_PART_NO, 0);
  2296. }
  2297. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  2298. * FUNCTION:
  2299. * ComstdGetAutoDetectResults
  2300. *
  2301. * DESCRIPTION:
  2302. *
  2303. *
  2304. * ARGUMENTS:
  2305. *
  2306. *
  2307. * RETURNS:
  2308. *
  2309. */
  2310. int ComstdGetAutoDetectResults(void *pvData, BYTE *bByteSize,
  2311. BYTE *bParity, BYTE *bStopBits)
  2312. {
  2313. ST_STDCOM *pstPrivate = (ST_STDCOM *)pvData;
  2314. assert(bByteSize);
  2315. assert(bParity);
  2316. assert(bStopBits);
  2317. if (pstPrivate->fADReconfigure)
  2318. {
  2319. *bByteSize = (BYTE)pstPrivate->stWorkSettings.nDataBits;
  2320. *bParity = (BYTE)pstPrivate->stWorkSettings.nParity;
  2321. *bStopBits = (BYTE)pstPrivate->stWorkSettings.nStopBits;
  2322. }
  2323. DBG_AD("DBG_AD: ComstdGetAutoDetectResults returning %d\r\n",
  2324. pstPrivate->fADReconfigure, 0,0,0,0);
  2325. DBG_AD(" (bits = %d, parity = %d, stops = %d)\r\n",
  2326. *bByteSize, *bParity, *bStopBits, 0,0);
  2327. return pstPrivate->fADReconfigure;
  2328. }
  2329. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  2330. * FUNCTION:
  2331. * ComstdSettingsToDCB
  2332. *
  2333. * DESCRIPTION:
  2334. *
  2335. *
  2336. * ARGUMENTS:
  2337. *
  2338. *
  2339. * RETURNS:
  2340. *
  2341. */
  2342. static void ComstdSettingsToDCB(ST_STDCOM_SETTINGS *pstSettings, DCB *pstDcb)
  2343. {
  2344. unsigned afHandshake;
  2345. afHandshake = pstSettings->afHandshake;
  2346. // fill in device control block
  2347. pstDcb->BaudRate = (DWORD)pstSettings->lBaud;
  2348. pstDcb->fBinary = 1;
  2349. pstDcb->fParity = 1;
  2350. pstDcb->fOutxCtsFlow = (BYTE)((bittest(afHandshake, HANDSHAKE_SND_CTS)) ? 1 : 0);
  2351. pstDcb->fOutxDsrFlow = (BYTE)(bittest(afHandshake, HANDSHAKE_SND_DSR) ? 1 : 0);
  2352. pstDcb->fDtrControl = bittest(afHandshake, HANDSHAKE_RCV_DTR) ?
  2353. DTR_CONTROL_HANDSHAKE : DTR_CONTROL_ENABLE;
  2354. pstDcb->fDsrSensitivity = 0;
  2355. pstDcb->fTXContinueOnXoff = TRUE;
  2356. pstDcb->fOutX = (BYTE)(bittest(afHandshake, HANDSHAKE_SND_X) ? 1 :0);
  2357. pstDcb->fInX = (BYTE)(bittest(afHandshake, HANDSHAKE_RCV_X) ? 1 :0);
  2358. pstDcb->fErrorChar = 0;
  2359. pstDcb->fNull = 0;
  2360. pstDcb->fRtsControl = bittest(afHandshake, HANDSHAKE_RCV_RTS) ?
  2361. RTS_CONTROL_HANDSHAKE : RTS_CONTROL_ENABLE;
  2362. pstDcb->fAbortOnError = 1; // so we can count all errors
  2363. pstDcb->XonLim = 80;
  2364. pstDcb->XoffLim = 200;
  2365. pstDcb->ByteSize = (BYTE)pstSettings->nDataBits;
  2366. pstDcb->Parity = (BYTE)pstSettings->nParity;
  2367. pstDcb->StopBits = (BYTE)pstSettings->nStopBits;
  2368. pstDcb->XonChar = pstSettings->chXON;
  2369. pstDcb->XoffChar = pstSettings->chXOFF;
  2370. }
  2371. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  2372. * FUNCTION:
  2373. * ComstdDCBToSettings
  2374. *
  2375. * DESCRIPTION:
  2376. *
  2377. *
  2378. * ARGUMENTS:
  2379. *
  2380. *
  2381. * RETURNS:
  2382. *
  2383. */
  2384. static void ComstdDCBToSettings(DCB *pstDcb, ST_STDCOM_SETTINGS *pstSettings)
  2385. {
  2386. pstSettings->lBaud = (long)pstDcb->BaudRate;
  2387. pstSettings->afHandshake = 0;
  2388. if (pstDcb->fOutxCtsFlow)
  2389. bitset(pstSettings->afHandshake, HANDSHAKE_SND_CTS);
  2390. if (pstDcb->fOutxDsrFlow)
  2391. bitset(pstSettings->afHandshake, HANDSHAKE_SND_DSR);
  2392. if (pstDcb->fDtrControl == DTR_CONTROL_HANDSHAKE)
  2393. bitset(pstSettings->afHandshake, HANDSHAKE_RCV_DTR);
  2394. if (pstDcb->fOutX)
  2395. bitset(pstSettings->afHandshake, HANDSHAKE_SND_X);
  2396. if (pstDcb->fInX)
  2397. bitset(pstSettings->afHandshake, HANDSHAKE_RCV_X);
  2398. if (pstDcb->fRtsControl == RTS_CONTROL_HANDSHAKE)
  2399. bitset(pstSettings->afHandshake, HANDSHAKE_RCV_RTS);
  2400. pstSettings->nDataBits = pstDcb->ByteSize;
  2401. pstSettings->nParity = pstDcb->Parity;
  2402. pstSettings->nStopBits = pstDcb->StopBits;
  2403. pstSettings->chXON = pstDcb->XonChar;
  2404. pstSettings->chXOFF = pstDcb->XoffChar;
  2405. }
  2406. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  2407. * FUNCTION: DeviceBreakTimerProc
  2408. *
  2409. * DESCRIPTION:
  2410. * Called when the break timer goes off. A timer is started whenever we
  2411. * set the break signal on. It goes off after the break signal duration.
  2412. * This function clears the break signal and destroys the timer
  2413. *
  2414. * ARGUMENTS:
  2415. * dwData -- A value stored when the timer is created. Contains pstPrivate
  2416. *
  2417. * RETURNS:
  2418. *
  2419. */
  2420. static void DeviceBreakTimerProc(void *pvData, long ulSince)
  2421. {
  2422. ST_STDCOM *pstPrivate = (ST_STDCOM *)pvData;
  2423. if (pstPrivate)
  2424. {
  2425. TimerDestroy(&pstPrivate->hTmrBreak); // this is a one-shot op
  2426. ClearCommBreak(pstPrivate->hWinComm); // have Win comm driver do it
  2427. pstPrivate->fBreakSignalOn = FALSE;
  2428. }
  2429. return;
  2430. }
  2431. #if 0
  2432. void StdcomRecordErrors(ST_STDCOM *pstPrivate, int iErrorBits)
  2433. {
  2434. if (bittest(iErrorBits, CE_FRAME | CE_OVERRUN | CE_RXOVER | CE_RXPARITY))
  2435. {
  2436. if (bittest(iErrorBits, CE_FRAME))
  2437. ++pstPrivate->nFramingErrors;
  2438. if (bittest(iErrorBits, CE_OVERRUN))
  2439. ++pstPrivate->nOverrunErrors;
  2440. if (bittest(iErrorBits, CE_RXOVER))
  2441. ++pstPrivate->nOverflowErrors;
  2442. if (bittest(iErrorBits, CE_RXPARITY))
  2443. ++pstPrivate->nParityErrors;
  2444. }
  2445. }
  2446. /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  2447. * FUNCTION: DeviceReportError
  2448. *
  2449. * DESCRIPTION:
  2450. *
  2451. *
  2452. * ARGUMENTS:
  2453. *
  2454. *
  2455. * RETURNS:
  2456. *
  2457. */
  2458. void DeviceReportError(ST_STDCOM *pstPrivate, UINT uiStringID,
  2459. LPSTR pszOptInfo, BOOL fFirstOnly)
  2460. {
  2461. CHAR szFmtString[250];
  2462. CHAR szErrString[250];
  2463. if (LoadString(hinstDLL, uiStringID, szFmtString, sizeof(szFmtString) / sizeof(TCHAR)) > 0)
  2464. {
  2465. wsprintf(szErrString, szFmtString, pszOptInfo);
  2466. ComReportError(pstPrivate->hCom, 0, szErrString, fFirstOnly);
  2467. }
  2468. }
  2469. #endif