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.

953 lines
28 KiB

  1. #include "precomp.h"
  2. DEBUG_FILEZONE(ZONE_T120_T123PSTN);
  3. /* Comport.cpp
  4. *
  5. * Copyright (c) 1993-1995 by DataBeam Corporation, Lexington, KY
  6. *
  7. * Abstract:
  8. * This is the implementation file for the ComPort class. This class
  9. * controls a specific Windows Comm port. The main purpose of this class
  10. * is to put the Windows specific comm calls in one class.
  11. *
  12. * Private Instance Variables:
  13. * m_hCommLink - Handle returned by Windows when you open
  14. * a com port
  15. * Tx_Buffer_Size - Output buffer size, Win32 buffer
  16. * Byte_Count - Represents total number of bytes transmitted
  17. * over the comm port
  18. * Last_Byte_Count - We have a timer that expires every X
  19. * seconds. It reports the total number of
  20. * bytes transmitted if Last_Byte_Count is not
  21. * equal to the Byte_Count. This reduces the
  22. * number of prints that occur
  23. * m_cbReadBufferSize - Buffer size of the ComPort's internal
  24. * buffer size.
  25. * m_pbReadBuffer - Address of our own internal buffer.
  26. * m_nReadBufferOffset - Keeps track of the number of bytes read
  27. * by the user via DataIndication calls.
  28. * m_cbRead - Number of bytes read via the last Windows
  29. * ReadFile() call.
  30. * m_hevtPendingWrite - Event object used with Windows WriteFile()
  31. * call.
  32. * m_hevtPendingRead - Event object used with Windows ReadFile()
  33. * call.
  34. * Write_Event_Object - Pointer to EventObject structure used with
  35. * the WriteFile() call.
  36. * Read_Event_Object - Pointer to EventObject structure used with
  37. * the ReadFile() call.
  38. * RLSD_Event_Object - Pointer to EventObject structure used with
  39. * the WaitCommEvent() call.
  40. * m_WriteOverlapped - Overlapped I/O structure used with the
  41. * Write event.
  42. * m_ReadOverlapped - Overlapped I/O structure used with the
  43. * Read event.
  44. * Event_Mask - Windows mask that specifies the events
  45. * that we are interested in.
  46. * Read_Active - TRUE if a ReadFile() function is active.
  47. * Write_Active - TRUE if a WriteFile() function is active.
  48. * Higher_Layer - Pointer to higher ProtocolLayer layer
  49. * Port_Configuration - Pointer to PortConfiguration structure.
  50. * Default_Com_Timeouts - This structure holds the Com timeout values
  51. * that Win32 had set as the default values.
  52. * When we are finished with the port, we
  53. * will restore these values
  54. *
  55. * Caveats:
  56. * None.
  57. *
  58. * Authors:
  59. * James P. Galvin
  60. * James W. Lawwill
  61. */
  62. #include "comport.h"
  63. /*
  64. * ComPort::ComPort (
  65. * PTransportResources transport_resources,
  66. * IObject * owner_object,
  67. * ULONG message_base,
  68. * ULONG handle,
  69. * PPortConfiguration port_configuration,
  70. * PhysicalHandle physical_handle)
  71. *
  72. * Public
  73. *
  74. * Functional Description:
  75. * This is the constructor for the ComPort class. It initializes internal
  76. * variables from the configuration file.
  77. */
  78. ComPort::ComPort
  79. (
  80. TransportController *owner_object,
  81. ULONG message_base,
  82. PLUGXPRT_PARAMETERS *pParams,
  83. PhysicalHandle hCommLink, // physical handle
  84. HANDLE hevtClose
  85. )
  86. :
  87. m_hCommLink(hCommLink),
  88. m_hevtClose(hevtClose),
  89. m_hevtPendingRead(NULL),
  90. m_hevtPendingWrite(NULL),
  91. m_hCommLink2(NULL), // two places can call Release, one in main thread, the other in worker thread by write event
  92. m_cRef(2),
  93. m_fClosed(FALSE)
  94. {
  95. m_pController = owner_object;
  96. m_nMsgBase = message_base;
  97. Automatic_Disconnect = FALSE;
  98. Count_Errors_On_ReadFile = 0;
  99. m_hevtPendingRead = ::CreateEvent(NULL, TRUE, FALSE, NULL);
  100. m_hevtPendingWrite = ::CreateEvent(NULL, TRUE, FALSE, NULL);
  101. ASSERT(m_hevtPendingRead && m_hevtPendingWrite);
  102. ::ZeroMemory(&m_ReadOverlapped, sizeof(m_ReadOverlapped));
  103. m_ReadOverlapped.hEvent = m_hevtPendingRead;
  104. ::ZeroMemory(&m_WriteOverlapped, sizeof(m_WriteOverlapped));
  105. m_WriteOverlapped.hEvent = m_hevtPendingWrite;
  106. /*
  107. ** Initialize internal variables
  108. */
  109. Byte_Count = 0;
  110. Last_Byte_Count = 0;
  111. m_pbReadBuffer = NULL;
  112. Read_Active = FALSE;
  113. m_nReadBufferOffset = 0;
  114. Read_Event_Object = NULL;
  115. Write_Active = FALSE;
  116. Write_Event_Object = NULL;
  117. DCB dcb;
  118. ::ZeroMemory(&dcb, sizeof(dcb));
  119. if (::GetCommState(m_hCommLink, &dcb)) // address of communications properties structure
  120. {
  121. Baud_Rate = dcb.BaudRate;
  122. }
  123. else
  124. {
  125. Baud_Rate = DEFAULT_BAUD_RATE;
  126. }
  127. // default settings
  128. Call_Control_Type = DEFAULT_PSTN_CALL_CONTROL;
  129. Tx_Buffer_Size = DEFAULT_TX_BUFFER_SIZE;
  130. Rx_Buffer_Size = DEFAULT_RX_BUFFER_SIZE;
  131. m_cbReadBufferSize = DEFAULT_INTERNAL_RX_BUFFER_SIZE;
  132. // get new parameters
  133. if (NULL != pParams)
  134. {
  135. if (PSTN_PARAM__CALL_CONTROL & pParams->dwFlags)
  136. {
  137. Call_Control_Type = pParams->eCallControl;
  138. }
  139. if (PSTN_PARAM__READ_FILE_BUFFER_SIZE & pParams->dwFlags)
  140. {
  141. if (1024 <= pParams->cbReadFileBufferSize)
  142. {
  143. m_cbReadBufferSize = pParams->cbReadFileBufferSize;
  144. }
  145. }
  146. if (PSTN_PARAM__PHYSICAL_LAYER_SEND_BUFFER_SIZE & pParams->dwFlags)
  147. {
  148. if (DEFAULT_TX_BUFFER_SIZE <= pParams->cbPhysicalLayerSendBufferSize)
  149. {
  150. Tx_Buffer_Size = pParams->cbPhysicalLayerSendBufferSize;
  151. }
  152. }
  153. if (PSTN_PARAM__PHSYICAL_LAYER_RECV_BUFFER_SIZE & pParams->dwFlags)
  154. {
  155. if (1024 <= pParams->cbPhysicalLayerReceiveBufferSize)
  156. {
  157. Rx_Buffer_Size = pParams->cbPhysicalLayerReceiveBufferSize;
  158. }
  159. }
  160. }
  161. }
  162. /*
  163. * ComPort::~ComPort (void)
  164. *
  165. * Public
  166. *
  167. * Functional Description:
  168. * This is the destructor for the Comport class. It releases all memory
  169. * that was used by the class and deletes all timers. It also closes the
  170. * com port
  171. */
  172. typedef BOOL (WINAPI *LPFN_CANCEL_IO) (HANDLE);
  173. ComPort::~ComPort(void)
  174. {
  175. // hopefully the worker thread is able to clean up all the read and write operations
  176. delete [] m_pbReadBuffer;
  177. m_pbReadBuffer = NULL;
  178. }
  179. LONG ComPort::Release(void)
  180. {
  181. Close ();
  182. HINSTANCE hLib = ::LoadLibrary("kernel32.dll");
  183. if (NULL != hLib)
  184. {
  185. LPFN_CANCEL_IO pfnCancelIo = (LPFN_CANCEL_IO) ::GetProcAddress(hLib, "CancelIo");
  186. if (NULL != pfnCancelIo)
  187. {
  188. (*pfnCancelIo)(m_hCommLink2);
  189. }
  190. ::FreeLibrary(hLib);
  191. }
  192. COMMTIMEOUTS com_timeouts, com_timeouts_save;
  193. if (::GetCommTimeouts(m_hCommLink2, &com_timeouts_save))
  194. {
  195. /*
  196. ** We are setting these timeout values to 0 because we were
  197. ** getting a VxD fault under Windows 95 when they were set to
  198. ** their normal values.
  199. */
  200. ::ZeroMemory(&com_timeouts, sizeof(com_timeouts));
  201. ::SetCommTimeouts(m_hCommLink2, &com_timeouts);
  202. /*
  203. ** Abort any ReadFile() or WriteFile() operations
  204. */
  205. ::PurgeComm(m_hCommLink2, PURGE_TXABORT | PURGE_RXABORT);
  206. /*
  207. ** Set the timeouts to their original state
  208. */
  209. ::SetCommTimeouts(m_hCommLink2, &com_timeouts_save);
  210. }
  211. // decrement the reference count
  212. if (! ::InterlockedDecrement(&m_cRef))
  213. {
  214. delete this;
  215. return 0;
  216. }
  217. return m_cRef;
  218. }
  219. /*
  220. * ComPortError ComPort::Open (void)
  221. *
  222. * Public
  223. *
  224. * Functional Description:
  225. * This function opens the comm port and configures it with the values
  226. * found in the configuration object.
  227. */
  228. ComPortError ComPort::Open(void)
  229. {
  230. BOOL fRet;
  231. ComPortError rc;
  232. TRACE_OUT(("ComPort:: TX size = %d RX size = %d Int Rx Size = %d",
  233. Tx_Buffer_Size, Rx_Buffer_Size, m_cbReadBufferSize));
  234. if (NULL == m_hevtPendingRead || NULL == m_hevtPendingWrite)
  235. {
  236. ERROR_OUT(("ComPort: Error create pending read/write events"));
  237. ReportInitializationFailure(COMPORT_INITIALIZATION_FAILED);
  238. return (COMPORT_INITIALIZATION_FAILED);
  239. }
  240. // allocate read buffer
  241. TRACE_OUT(("Comport: Internal Rx Buffer Size = %ld", m_cbReadBufferSize));
  242. DBG_SAVE_FILE_LINE
  243. m_pbReadBuffer = new BYTE[m_cbReadBufferSize];
  244. m_nReadBufferOffset = 0;
  245. if (m_pbReadBuffer == NULL)
  246. {
  247. ERROR_OUT(("ComPort: Error allocating memory = %d", ::GetLastError()));
  248. ReportInitializationFailure(COMPORT_INITIALIZATION_FAILED);
  249. return (COMPORT_INITIALIZATION_FAILED);
  250. }
  251. /*
  252. ** Issue a read to the com port.
  253. ** We are going to continue to issue Readfile() calls
  254. ** until we get into a wait state. 99.9999% of the
  255. ** time, we will only issue the first ReadFile() and
  256. ** it will immediately block waiting for data.
  257. */
  258. while (1)
  259. {
  260. m_cbRead = 0;
  261. fRet = ::ReadFile(m_hCommLink, m_pbReadBuffer, m_cbReadBufferSize, &m_cbRead, &m_ReadOverlapped);
  262. if (! fRet)
  263. {
  264. DWORD dwErr = ::GetLastError();
  265. if (dwErr == ERROR_IO_PENDING)
  266. {
  267. Read_Active = TRUE;
  268. break;
  269. }
  270. else
  271. {
  272. ERROR_OUT(("ComPort: Error on ReadFile = %d", dwErr));
  273. ReportInitializationFailure(COMPORT_INITIALIZATION_FAILED);
  274. return (COMPORT_INITIALIZATION_FAILED);
  275. }
  276. }
  277. }
  278. /*
  279. ** If this is a synchronous read, wait for the event object to be
  280. ** set before returning.
  281. */
  282. if (Call_Control_Type == PLUGXPRT_PSTN_CALL_CONTROL_MANUAL)
  283. {
  284. ::WaitForSingleObject(m_hevtPendingRead, SYNCHRONOUS_WRITE_TIMEOUT*10);
  285. fRet = GetOverlappedResult(m_hCommLink, &m_ReadOverlapped, &m_cbRead, FALSE);
  286. if (! fRet)
  287. {
  288. ::PurgeComm(m_hCommLink, PURGE_RXABORT);
  289. }
  290. }
  291. /*
  292. ** Create and fill in the EventObject. It is then
  293. ** appended to the PSTN Event_List so that the EventManager
  294. ** can wait for the event to occur.
  295. */
  296. DBG_SAVE_FILE_LINE
  297. Read_Event_Object = new EventObject;
  298. Read_Event_Object -> event = m_hevtPendingRead;
  299. Read_Event_Object -> delete_event = FALSE;
  300. Read_Event_Object -> comport = this;
  301. Read_Event_Object -> hCommLink = m_hCommLink;
  302. Read_Event_Object -> event_type = READ_EVENT;
  303. g_pPSTNEventList->append((DWORD_PTR) Read_Event_Object);
  304. g_fEventListChanged = TRUE;
  305. Write_Active = FALSE;
  306. /*
  307. ** Create and fill in the EventObject. It is then
  308. ** appended to the PSTN Event_List so that the EventManager
  309. ** can wait for the event to occur.
  310. */
  311. DBG_SAVE_FILE_LINE
  312. Write_Event_Object = new EventObject;
  313. Write_Event_Object -> event = m_hevtPendingWrite;
  314. Write_Event_Object -> delete_event = FALSE;
  315. Write_Event_Object -> comport = this;
  316. Write_Event_Object -> hCommLink = m_hCommLink;
  317. Write_Event_Object -> event_type = WRITE_EVENT;
  318. g_pPSTNEventList->append((DWORD_PTR) Write_Event_Object);
  319. g_fEventListChanged = TRUE;
  320. return (COMPORT_NO_ERROR);
  321. }
  322. /*
  323. * ComPortError ComPort::Close (void)
  324. *
  325. * Public
  326. *
  327. * Functional Description:
  328. * This function makes the necessary Windows calls to close the Com
  329. * port. It first clears the DTR signal to notify the modem.
  330. */
  331. ComPortError ComPort::Close(void)
  332. {
  333. if (! m_fClosed)
  334. {
  335. m_fClosed = TRUE;
  336. /*
  337. ** Reset the Activity flags.
  338. */
  339. Write_Active = FALSE;
  340. Read_Active = FALSE;
  341. // we do not close the handle here, T.120 will do it.
  342. m_hCommLink2 = m_hCommLink;
  343. m_hCommLink = INVALID_HANDLE_VALUE;
  344. /*
  345. ** Notify the event manager that these events need to be deleted.
  346. ** It is important for the event manager to realize that when the
  347. ** delete_event is set to TRUE, he can no longer access this object.
  348. */
  349. if (Write_Event_Object != NULL)
  350. {
  351. ::CloseHandle(Write_Event_Object->event);
  352. g_pPSTNEventList->remove((DWORD_PTR) Write_Event_Object);
  353. delete Write_Event_Object;
  354. }
  355. if (Read_Event_Object != NULL)
  356. {
  357. Read_Event_Object -> delete_event = TRUE;
  358. ::SetEvent(m_hevtPendingRead);
  359. }
  360. // let the worker thread to pick up the work
  361. ::Sleep(50);
  362. }
  363. return COMPORT_NO_ERROR;
  364. }
  365. /*
  366. * ComPortError ComPort::Reset (void)
  367. *
  368. * Public
  369. *
  370. * Functional Description:
  371. * This function clears the DTR signal on the Com port.
  372. */
  373. ComPortError ComPort::Reset(void)
  374. {
  375. return COMPORT_NO_ERROR;
  376. }
  377. /*
  378. * ComPortError ComPort::ReleaseReset (void)
  379. *
  380. * Public
  381. *
  382. * Functional Description:
  383. * This function releases the previous reset. It set the DTR signal on
  384. * the com port.
  385. */
  386. ComPortError ComPort::ReleaseReset(void)
  387. {
  388. return COMPORT_NO_ERROR;
  389. }
  390. /*
  391. * ULONG ComPort::GetBaudRate (void)
  392. *
  393. * Public
  394. *
  395. * Functional Description:
  396. * This function returns the baud rate of the port
  397. */
  398. /*
  399. * ProtocolLayerError ComPort::DataRequest (
  400. * ULONG,
  401. * LPBYTE buffer_address,
  402. * ULONG length,
  403. *
  404. * Public
  405. *
  406. * Functional Description:
  407. * This function is called to send data out the port in an asynchronous
  408. * manner. In other words, we will return from the function before all
  409. * of the bytes are actually written to the modem.
  410. */
  411. ProtocolLayerError ComPort::DataRequest(ULONG_PTR,
  412. LPBYTE buffer_address,
  413. ULONG length,
  414. ULONG *bytes_accepted)
  415. {
  416. return WriteData(FALSE, buffer_address, length, bytes_accepted);
  417. }
  418. /*
  419. * ProtocolLayerError ComPort::SynchronousDataRequest (
  420. * LPBYTE buffer_address,
  421. * ULONG length,
  422. * PULong bytes_accepted)
  423. *
  424. * Public
  425. *
  426. * Functional Description:
  427. * This function is called to send data out the port in a synchronous
  428. * manner. In other words, we will not return from the function until
  429. * all of the bytes are actually written to the modem or a timeout occurs.
  430. */
  431. ProtocolLayerError ComPort::SynchronousDataRequest(
  432. LPBYTE buffer_address,
  433. ULONG length,
  434. ULONG *bytes_accepted)
  435. {
  436. return WriteData(TRUE, buffer_address, length, bytes_accepted);
  437. }
  438. /*
  439. * ProtocolLayerError ComPort::WriteData (
  440. * BOOL synchronous,
  441. * LPBYTE buffer_address,
  442. * ULONG length,
  443. * PULong bytes_accepted)
  444. *
  445. * Functional Description
  446. * This function makes the Win32 calls to write data to the port.
  447. *
  448. * Formal Parameters
  449. * synchronous - (i) TRUE, if we should wait for the write to
  450. * complete before returning.
  451. * buffer_address - (i) Address of the data to write.
  452. * length - (i) Length of the data to write.
  453. * bytes_accepted - (i) Actually number of bytes written.
  454. *
  455. * Return Value
  456. * PROTOCOL_LAYER_ERROR - Port not open
  457. * PROTOCOL_LAYER_NO_ERROR - No error occured
  458. *
  459. *
  460. * Side Effects
  461. * None.
  462. *
  463. * Caveats
  464. * None
  465. */
  466. ProtocolLayerError ComPort::WriteData
  467. (
  468. BOOL synchronous,
  469. LPBYTE buffer_address,
  470. ULONG length,
  471. PULong bytes_accepted
  472. )
  473. {
  474. COMSTAT com_status;
  475. ULONG com_error;
  476. ULONG byte_count;
  477. ULONG bytes_written;
  478. BOOL fRet;
  479. *bytes_accepted = 0;
  480. if (m_hCommLink == INVALID_HANDLE_VALUE)
  481. {
  482. return (PROTOCOL_LAYER_ERROR);
  483. }
  484. if (Write_Active)
  485. {
  486. return (PROTOCOL_LAYER_NO_ERROR);
  487. }
  488. /*
  489. ** Determine the amount of space left in the buffer
  490. */
  491. ::ZeroMemory(&com_status, sizeof(com_status));
  492. ::ClearCommError(m_hCommLink, &com_error, &com_status);
  493. if (length > (Tx_Buffer_Size - com_status.cbOutQue))
  494. {
  495. byte_count = Tx_Buffer_Size - com_status.cbOutQue;
  496. }
  497. else
  498. {
  499. byte_count = length;
  500. }
  501. ::ZeroMemory(&m_WriteOverlapped, sizeof(m_WriteOverlapped));
  502. m_WriteOverlapped.hEvent = m_hevtPendingWrite;
  503. fRet = ::WriteFile(m_hCommLink, buffer_address, byte_count, &bytes_written, &m_WriteOverlapped);
  504. /*
  505. ** If this is a synchronous write, wait for the event object to be
  506. ** set before returning.
  507. */
  508. if (synchronous)
  509. {
  510. ::WaitForSingleObject(m_hevtPendingWrite, SYNCHRONOUS_WRITE_TIMEOUT);
  511. fRet = ::GetOverlappedResult(m_hCommLink, &m_WriteOverlapped, &bytes_written, FALSE);
  512. if (! fRet)
  513. {
  514. WARNING_OUT(("ComPort::WriteData: purge comm"));
  515. ::PurgeComm(m_hCommLink, PURGE_TXABORT);
  516. }
  517. ::ResetEvent(m_WriteOverlapped.hEvent);
  518. }
  519. if (! fRet)
  520. {
  521. if (::GetLastError () == ERROR_IO_PENDING)
  522. {
  523. Write_Active = TRUE;
  524. *bytes_accepted = byte_count;
  525. Byte_Count += byte_count;
  526. }
  527. else
  528. {
  529. TRACE_OUT(("ComPort: DataRequest: Error on WriteFile = %d", ::GetLastError()));
  530. }
  531. }
  532. else
  533. {
  534. if (bytes_written != byte_count)
  535. {
  536. TRACE_OUT(("ComPort: DataRequest: Error on WriteFile bytes written != bytes requested"));
  537. }
  538. *bytes_accepted = byte_count;
  539. /*
  540. ** Increment Byte_Count
  541. */
  542. Byte_Count += bytes_written;
  543. }
  544. return (PROTOCOL_LAYER_NO_ERROR);
  545. }
  546. /*
  547. * ProtocolLayerError ComPort::RegisterHigherLayer (
  548. * ULONG,
  549. * PMemoryManager,
  550. * IProtocolLayer * higher_layer)
  551. *
  552. * Public
  553. *
  554. * Functional Description:
  555. * This function is called by an object that wants to receive the data
  556. * read from the com port.
  557. */
  558. ProtocolLayerError ComPort::RegisterHigherLayer(ULONG_PTR, PMemoryManager,
  559. IProtocolLayer *pMux)
  560. {
  561. m_pMultiplexer = pMux;
  562. return (PROTOCOL_LAYER_NO_ERROR);
  563. }
  564. /*
  565. * ProtocolLayerError ComPort::RemoveHigherLayer (
  566. * USHORT)
  567. *
  568. * Public
  569. *
  570. * Functional Description:
  571. * This function is called by an object that no longer wants to receive
  572. * the data from the com port.
  573. */
  574. ProtocolLayerError ComPort::RemoveHigherLayer(ULONG_PTR)
  575. {
  576. m_pMultiplexer = NULL;
  577. return (PROTOCOL_LAYER_NO_ERROR);
  578. }
  579. /*
  580. * ProtocolLayerError ComPort::PollReceiver (
  581. * ULONG)
  582. *
  583. * Public
  584. *
  585. * Functional Description:
  586. * This function is called to take the data that we have received from
  587. * the port and pass it on up to the registered layer.
  588. */
  589. ProtocolLayerError ComPort::PollReceiver(void)
  590. {
  591. BOOL issue_read = FALSE;
  592. ULONG bytes_accepted;
  593. BOOL fRet;
  594. if (m_pMultiplexer == NULL || m_hCommLink == INVALID_HANDLE_VALUE)
  595. {
  596. return (PROTOCOL_LAYER_ERROR);
  597. }
  598. /*
  599. ** This event can occur if we have completed a read but the higher layers
  600. ** have not accepted all of the data. So, before we issue another
  601. ** ReadFile() we are going to send the pending data on up.
  602. */
  603. if (! Read_Active)
  604. {
  605. if (m_cbRead)
  606. {
  607. m_pMultiplexer->DataIndication(m_pbReadBuffer, m_cbRead - m_nReadBufferOffset, &bytes_accepted);
  608. if (bytes_accepted > (m_cbRead - m_nReadBufferOffset))
  609. {
  610. ERROR_OUT(("ComPort: PollReceiver1: ERROR: Higher layer accepted too many bytes"));
  611. }
  612. m_nReadBufferOffset += bytes_accepted;
  613. if (m_nReadBufferOffset == m_cbRead)
  614. {
  615. issue_read = TRUE;
  616. m_cbRead = 0;
  617. m_nReadBufferOffset = 0;
  618. }
  619. }
  620. else
  621. {
  622. issue_read = TRUE;
  623. }
  624. }
  625. /*
  626. ** Issue a ReadFile () and process any data received.
  627. */
  628. while (issue_read)
  629. {
  630. m_cbRead = 0;
  631. m_nReadBufferOffset = 0;
  632. ::ZeroMemory(&m_ReadOverlapped, sizeof(m_ReadOverlapped));
  633. m_ReadOverlapped.hEvent = m_hevtPendingRead;
  634. fRet = ::ReadFile(m_hCommLink, m_pbReadBuffer, m_cbReadBufferSize, &m_cbRead, &m_ReadOverlapped);
  635. if (! fRet)
  636. {
  637. if (::GetLastError() == ERROR_IO_PENDING)
  638. {
  639. Read_Active = TRUE;
  640. }
  641. else
  642. {
  643. WARNING_OUT(("ComPort: Error on ReadFile = %d", ::GetLastError()));
  644. if (Count_Errors_On_ReadFile++ == DEFAULT_COUNT_OF_READ_ERRORS)
  645. {
  646. WARNING_OUT(("ComPort: %d Errors on ReadFile, closing the connection", Count_Errors_On_ReadFile));
  647. Close();
  648. return (PROTOCOL_LAYER_ERROR);
  649. }
  650. }
  651. issue_read = FALSE;
  652. }
  653. else
  654. {
  655. if (m_pMultiplexer != NULL)
  656. {
  657. m_pMultiplexer->DataIndication(m_pbReadBuffer, m_cbRead, &bytes_accepted);
  658. if (bytes_accepted > m_cbRead)
  659. {
  660. ERROR_OUT(("ComPort: PollReceiver: ERROR: Higher layer accepted too many bytes"));
  661. }
  662. m_nReadBufferOffset += bytes_accepted;
  663. if (m_nReadBufferOffset != m_cbRead)
  664. {
  665. issue_read = FALSE;
  666. }
  667. }
  668. else
  669. {
  670. issue_read = FALSE;
  671. }
  672. }
  673. }
  674. return (PROTOCOL_LAYER_NO_ERROR);
  675. }
  676. /*
  677. * ProtocolLayerError ComPort::GetParameters (
  678. * ULONG,
  679. * USHORT * max_packet_size,
  680. * USHORT * prepend,
  681. * USHORT * append)
  682. *
  683. * Public
  684. *
  685. * Functional Description:
  686. * This function is called by an object to determine the maximum packet
  687. * size that this object expects. It also queries the number of bytes
  688. * it should skip on the front of a packet and append to the end of a
  689. * packet. The ComPort object is a stream device, so these parameters
  690. * don't really matter.
  691. */
  692. ProtocolLayerError ComPort::GetParameters
  693. (
  694. USHORT * max_packet_size,
  695. USHORT * prepend,
  696. USHORT * append
  697. )
  698. {
  699. /*
  700. ** max_packet_size set to 0xffff means that this object receives
  701. ** data in a stream format rather than a packet format. It does
  702. ** group data into packets, it handles data a byte at a time.
  703. ** Therefore, when a higher layer issues a DataRequest() to this
  704. ** object, it may not accept the whole data block, it may only
  705. ** accept part of it.
  706. **
  707. ** prepend is set to 0 because this object does not prepend any
  708. ** data to the beginning of a DataRequest() packet.
  709. **
  710. ** append is set to 0 because this object does not append any
  711. ** data to the end of a DataRequest() packet.
  712. */
  713. *max_packet_size = 0xffff;
  714. *prepend = 0;
  715. *append = 0;
  716. return (PROTOCOL_LAYER_NO_ERROR);
  717. }
  718. /*
  719. * void ComPort::ReportInitializationFailure (
  720. * PChar error_message)
  721. *
  722. * Functional Description
  723. * This routine simply reports an error to the user and closes the
  724. * Windows comm port. It does absolutely nothing if the Physical
  725. * API is disabled.
  726. *
  727. * Formal Parameters
  728. * error_message (i) - Pointer to error message
  729. *
  730. * Return Value
  731. * None
  732. *
  733. * Side Effects
  734. * None.
  735. *
  736. * Caveats
  737. * None
  738. */
  739. void ComPort::ReportInitializationFailure(ComPortError rc)
  740. {
  741. ERROR_OUT(("ComPort:: IO failure, rc=%d", rc));
  742. }
  743. /*
  744. * BOOL ComPort::ProcessReadEvent (void)
  745. *
  746. * Public
  747. *
  748. * Functional Description:
  749. * This function is called when a READ event is actually set. This means
  750. * that the read operation has completed or an error occured.
  751. */
  752. BOOL ComPort::ProcessReadEvent(void)
  753. {
  754. BOOL fRet;
  755. if (Read_Active)
  756. {
  757. if (WAIT_OBJECT_0 == ::WaitForSingleObject(m_hevtPendingRead, 0))
  758. {
  759. fRet = GetOverlappedResult(m_hCommLink, &m_ReadOverlapped, &m_cbRead, FALSE);
  760. if (fRet && m_cbRead == 0)
  761. {
  762. fRet = FALSE;
  763. }
  764. Read_Active = FALSE;
  765. ::ResetEvent(m_hevtPendingRead);
  766. }
  767. }
  768. else
  769. {
  770. ::ResetEvent(m_hevtPendingRead);
  771. }
  772. return fRet;
  773. }
  774. /*
  775. * BOOL ComPort::ProcessWriteEvent (void)
  776. *
  777. * Public
  778. *
  779. * Functional Description:
  780. * This function is called when a WRITE event is actually set. This means
  781. * that the write operation has completed or an error occured.
  782. */
  783. BOOL ComPort::ProcessWriteEvent(void)
  784. {
  785. ULONG bytes_written;
  786. BOOL fRet = FALSE;
  787. if (Write_Active)
  788. {
  789. if (WAIT_OBJECT_0 == ::WaitForSingleObject(m_hevtPendingWrite, 0))
  790. {
  791. fRet = ::GetOverlappedResult(m_hCommLink, &m_WriteOverlapped, &bytes_written, FALSE);
  792. if (! fRet)
  793. {
  794. DWORD dwErr = ::GetLastError();
  795. if (ERROR_IO_PENDING == dwErr)
  796. {
  797. TRACE_OUT(("ProcessWriteEvent: still pending"));
  798. }
  799. else
  800. {
  801. WARNING_OUT(("ProcessWriteEvent: ERROR = %d", dwErr));
  802. }
  803. }
  804. Write_Active = FALSE;
  805. ::ResetEvent(m_hevtPendingWrite);
  806. }
  807. }
  808. else
  809. {
  810. ::ResetEvent(m_hevtPendingWrite);
  811. }
  812. return fRet;
  813. }
  814. /*
  815. * ProtocolLayerError ComPort::DataIndication (
  816. * LPBYTE,
  817. * ULONG,
  818. * PULong)
  819. *
  820. * Public
  821. *
  822. * Functional Description:
  823. * This function is not used. It is only here because we inherit from
  824. * ProtocolLayer.
  825. */
  826. ProtocolLayerError ComPort::DataIndication(LPBYTE, ULONG, PULong)
  827. {
  828. return (PROTOCOL_LAYER_ERROR);
  829. }
  830. /*
  831. * ProtocolLayerError ComPort::DataRequest (
  832. * ULONG,
  833. * PMemory,
  834. * PULong)
  835. *
  836. * Public
  837. *
  838. * Functional Description:
  839. * This function is not used. It is only here because we inherit from
  840. * ProtocolLayer.
  841. */
  842. ProtocolLayerError ComPort::DataRequest(ULONG_PTR, PMemory, PULong)
  843. {
  844. return (PROTOCOL_LAYER_ERROR);
  845. }
  846. /*
  847. * ProtocolLayerError ComPort::PollTransmitter (
  848. * ULONG,
  849. * USHORT,
  850. * USHORT *,
  851. * USHORT *)
  852. *
  853. * Public
  854. *
  855. * Functional Description:
  856. * This function is not used. It is only here because we inherit from
  857. * ProtocolLayer.
  858. */
  859. ProtocolLayerError ComPort::PollTransmitter(ULONG_PTR, USHORT, USHORT *, USHORT *)
  860. {
  861. return (PROTOCOL_LAYER_ERROR);
  862. }
  863.