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.

1410 lines
48 KiB

  1. /*--------------------------------------------------------------------------
  2. *
  3. * Copyright (C) Cyclades Corporation, 1997-2001.
  4. * All rights reserved.
  5. *
  6. * Cyclades-Z Port Driver
  7. *
  8. * This file: cyzmodem.c
  9. *
  10. * Description: This module contains the code related to modem control
  11. * in the Cyclades-Z Port driver.
  12. *
  13. * Notes: This code supports Windows 2000 and Windows XP,
  14. * x86 and IA64 processors.
  15. *
  16. * Complies with Cyclades SW Coding Standard rev 1.3.
  17. *
  18. *--------------------------------------------------------------------------
  19. */
  20. /*-------------------------------------------------------------------------
  21. *
  22. * Change History
  23. *
  24. *--------------------------------------------------------------------------
  25. *
  26. *
  27. *--------------------------------------------------------------------------
  28. */
  29. #include "precomp.h"
  30. BOOLEAN
  31. CyzDecrementRTSCounter(
  32. IN PVOID Context
  33. );
  34. #ifdef ALLOC_PRAGMA
  35. #if 0
  36. #pragma alloc_text(PAGESER,CyzHandleReducedIntBuffer)
  37. #pragma alloc_text(PAGESER,CyzProdXonXoff)
  38. #pragma alloc_text(PAGESER,CyzHandleModemUpdate)
  39. #pragma alloc_text(PAGESER,CyzPerhapsLowerRTS)
  40. #pragma alloc_text(PAGESER,CyzStartTimerLowerRTS)
  41. #pragma alloc_text(PAGESER,CyzInvokePerhapsLowerRTS)
  42. #pragma alloc_text(PAGESER,CyzSetDTR)
  43. #pragma alloc_text(PAGESER,CyzClrDTR)
  44. #pragma alloc_text(PAGESER,CyzSetRTS)
  45. #pragma alloc_text(PAGESER,CyzClrRTS)
  46. #pragma alloc_text(PAGESER,CyzSetupNewHandFlow)
  47. #pragma alloc_text(PAGESER,CyzSetHandFlow)
  48. #pragma alloc_text(PAGESER,CyzTurnOnBreak)
  49. #pragma alloc_text(PAGESER,CyzTurnOffBreak)
  50. #pragma alloc_text(PAGESER,CyzPretendXoff)
  51. #pragma alloc_text(PAGESER,CyzPretendXon)
  52. #pragma alloc_text(PAGESER,CyzDecrementRTSCounter)
  53. #endif
  54. #endif
  55. BOOLEAN
  56. CyzSetDTR(
  57. IN PVOID Context
  58. )
  59. /*--------------------------------------------------------------------------
  60. CyzSetDTR()
  61. Routine Description: This routine which is only called at interrupt
  62. level is used to set the DTR in the modem control register.
  63. Arguments:
  64. Context - Really a pointer to the device extension.
  65. Return Value: This routine always returns FALSE.
  66. --------------------------------------------------------------------------*/
  67. {
  68. PCYZ_DEVICE_EXTENSION Extension = Context;
  69. struct CH_CTRL *ch_ctrl;
  70. ULONG rs_control;
  71. CyzDbgPrintEx(CYZFLOW, "Setting DTR for Port%d Pci%d\n",
  72. Extension->PortIndex+1,Extension->PciSlot);
  73. ch_ctrl = Extension->ChCtrl;
  74. rs_control = CYZ_READ_ULONG(&ch_ctrl->rs_control);
  75. rs_control |= C_RS_DTR;
  76. CYZ_WRITE_ULONG(&ch_ctrl->rs_control,rs_control);
  77. CyzIssueCmd(Extension,C_CM_IOCTLM,rs_control|C_RS_PARAM,FALSE);
  78. return FALSE;
  79. }
  80. BOOLEAN
  81. CyzClrDTR(
  82. IN PVOID Context
  83. )
  84. /*--------------------------------------------------------------------------
  85. CyzClrDTR()
  86. Routine Description: Clear DTR.
  87. Arguments:
  88. Context - Really a pointer to the device extension.
  89. Return Value: This routine always returns FALSE.
  90. --------------------------------------------------------------------------*/
  91. {
  92. PCYZ_DEVICE_EXTENSION Extension = Context;
  93. struct CH_CTRL *ch_ctrl;
  94. ULONG rs_control;
  95. CyzDbgPrintEx(CYZFLOW, "Clearing DTR for Port%d Pci%d\n",
  96. Extension->PortIndex+1,Extension->PciSlot);
  97. ch_ctrl = Extension->ChCtrl;
  98. rs_control = CYZ_READ_ULONG(&ch_ctrl->rs_control);
  99. rs_control &= ~C_RS_DTR;
  100. CYZ_WRITE_ULONG(&ch_ctrl->rs_control, rs_control);
  101. CyzIssueCmd(Extension,C_CM_IOCTLM,rs_control|C_RS_PARAM,FALSE);
  102. return FALSE;
  103. }
  104. BOOLEAN
  105. CyzSetRTS(
  106. IN PVOID Context
  107. )
  108. /*--------------------------------------------------------------------------
  109. CyzSetRTS()
  110. Routine Description: Set RTS.
  111. Arguments:
  112. Context - Really a pointer to the device extension.
  113. Return Value: This routine always returns FALSE.
  114. --------------------------------------------------------------------------*/
  115. {
  116. PCYZ_DEVICE_EXTENSION Extension = Context;
  117. struct CH_CTRL *ch_ctrl;
  118. ULONG rs_control;
  119. CyzDbgPrintEx(CYZFLOW, "Setting RTS for Port%d Pci%d\n",
  120. Extension->PortIndex+1,Extension->PciSlot);
  121. ch_ctrl = Extension->ChCtrl;
  122. rs_control = CYZ_READ_ULONG(&ch_ctrl->rs_control);
  123. rs_control |= C_RS_RTS;
  124. CYZ_WRITE_ULONG(&ch_ctrl->rs_control,rs_control);
  125. CyzIssueCmd(Extension,C_CM_IOCTLM,rs_control|C_RS_PARAM,FALSE);
  126. return FALSE;
  127. }
  128. BOOLEAN
  129. CyzClrRTS(
  130. IN PVOID Context
  131. )
  132. /*--------------------------------------------------------------------------
  133. CyzClrRTS()
  134. Routine Description: Clears RTS.
  135. Arguments:
  136. Context - Really a pointer to the device extension.
  137. Return Value: This routine always returns FALSE.
  138. --------------------------------------------------------------------------*/
  139. {
  140. PCYZ_DEVICE_EXTENSION Extension = Context;
  141. struct CH_CTRL *ch_ctrl;
  142. ULONG rs_control;
  143. CyzDbgPrintEx(CYZFLOW, "Clearing RTS for Port%d Pci%d\n",
  144. Extension->PortIndex+1,Extension->PciSlot);
  145. ch_ctrl = Extension->ChCtrl;
  146. rs_control = CYZ_READ_ULONG(&ch_ctrl->rs_control);
  147. rs_control &= ~C_RS_RTS;
  148. CYZ_WRITE_ULONG(&ch_ctrl->rs_control,rs_control);
  149. CyzIssueCmd(Extension,C_CM_IOCTLM,rs_control|C_RS_PARAM,FALSE);
  150. return FALSE;
  151. }
  152. BOOLEAN
  153. CyzSetupNewHandFlow(
  154. IN PCYZ_DEVICE_EXTENSION Extension,
  155. IN PSERIAL_HANDFLOW NewHandFlow
  156. )
  157. /*--------------------------------------------------------------------------
  158. CyzSetupNewHandFlow()
  159. Routine Description: This routine adjusts the flow control based on new
  160. control flow.
  161. Arguments:
  162. Extension - A pointer to the serial device extension.
  163. NewHandFlow - A pointer to a serial handflow structure.
  164. Return Value: This routine always returns FALSE.
  165. --------------------------------------------------------------------------*/
  166. {
  167. SERIAL_HANDFLOW New = *NewHandFlow;
  168. struct CH_CTRL *ch_ctrl;
  169. ULONG hw_flow;
  170. #if 0
  171. ULONG sw_flow;
  172. #endif
  173. // LOGENTRY(LOG_MISC, ZSIG_HANDSHAKE_SET,
  174. // Extension->PortIndex+1,
  175. // New.ControlHandShake,
  176. // New.FlowReplace);
  177. ch_ctrl = Extension->ChCtrl;
  178. // --- DTR signal
  179. if((!Extension->DeviceIsOpened) ||
  180. ((Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) !=
  181. (New.ControlHandShake & SERIAL_DTR_MASK))) {
  182. // It is an open or DTR has changed.
  183. CyzDbgPrintEx(CYZFLOW, "Processing DTR flow for Port%d Pci%d\n",
  184. Extension->PortIndex+1,Extension->PciSlot);
  185. if (New.ControlHandShake & SERIAL_DTR_MASK) { // set DTR.
  186. if((New.ControlHandShake&SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE) {
  187. // but we are doing DTR handshake.
  188. #ifdef FIRMWARE_HANDSHAKE
  189. hw_flow = CYZ_READ_ULONG(&ch_ctrl->hw_flow);
  190. hw_flow |= C_RS_DTR;
  191. CYZ_WRITE_ULONG(&ch_ctrl->hw_flow,hw_flow);
  192. #endif
  193. if ((Extension->BufferSize - New.XoffLimit) >
  194. Extension->CharsInInterruptBuffer) {
  195. if (Extension->RXHolding & CYZ_RX_DTR) {
  196. // DTR is low due to flow control
  197. if(Extension->CharsInInterruptBuffer >
  198. (ULONG)New.XonLimit) {
  199. CyzDbgPrintEx(CYZFLOW, "Removing DTR block on "
  200. "reception for Port%d Pci%d\n",
  201. Extension->PortIndex+1,Extension->PciSlot);
  202. Extension->RXHolding &= ~CYZ_RX_DTR;
  203. #ifndef FIRMWARE_HANDSHAKE
  204. CyzSetDTR(Extension);
  205. #endif
  206. }
  207. } else {
  208. #ifndef FIRMWARE_HANDSHAKE
  209. CyzSetDTR(Extension);
  210. #endif
  211. }
  212. } else {
  213. // DTR should go low because of handshake
  214. CyzDbgPrintEx(CYZFLOW, "Setting DTR block on reception "
  215. "for Port%d Pci%d\n",
  216. Extension->PortIndex+1,Extension->PciSlot);
  217. Extension->RXHolding |= CYZ_RX_DTR;
  218. #ifndef FIRMWARE_HANDSHAKE
  219. CyzClrDTR(Extension);
  220. #endif
  221. }
  222. } else {
  223. #ifdef FIRMWARE_HANDSHAKE
  224. hw_flow = CYZ_READ_ULONG(&ch_ctrl->hw_flow);
  225. hw_flow &= ~C_RS_DTR;
  226. CYZ_WRITE_ULONG(&ch_ctrl->hw_flow,hw_flow);
  227. #endif
  228. // no DTR handshake, check if it was active before.
  229. if (Extension->RXHolding & CYZ_RX_DTR) {
  230. CyzDbgPrintEx(CYZFLOW, "Removing dtr block of reception "
  231. "for Port%d Pci%d\n",
  232. Extension->PortIndex+1,Extension->PciSlot);
  233. Extension->RXHolding &= ~CYZ_RX_DTR;
  234. }
  235. CyzSetDTR(Extension);
  236. }
  237. } else { // reset DTR
  238. #ifdef FIRMWARE_HANDSHAKE
  239. hw_flow = CYZ_READ_ULONG(&ch_ctrl->hw_flow);
  240. hw_flow &= ~C_RS_DTR;
  241. CYZ_WRITE_ULONG(&ch_ctrl->hw_flow,hw_flow);
  242. #endif
  243. if (Extension->RXHolding & CYZ_RX_DTR) {
  244. CyzDbgPrintEx(CYZFLOW, "removing dtr block of reception for"
  245. " Port%d Pci%d\n",
  246. Extension->PortIndex+1,Extension->PciSlot);
  247. Extension->RXHolding &= ~CYZ_RX_DTR;
  248. }
  249. CyzClrDTR(Extension);
  250. }
  251. }
  252. // --- RTS signal
  253. if ((!Extension->DeviceIsOpened) ||
  254. ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) !=
  255. (New.FlowReplace & SERIAL_RTS_MASK))) {
  256. // It is an open or RTS has changed.
  257. CyzDbgPrintEx(CYZFLOW, "Processing RTS flow\n",
  258. Extension->PortIndex+1,Extension->PciSlot);
  259. if((New.FlowReplace&SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE) {//set RTS
  260. #ifdef FIRMWARE_HANDSHAKE
  261. hw_flow = CYZ_READ_ULONG(&ch_ctrl->hw_flow);
  262. hw_flow |= C_RS_RTS;
  263. CYZ_WRITE_ULONG(&ch_ctrl->hw_flow,hw_flow);
  264. #endif
  265. if ((Extension->BufferSize - New.XoffLimit) >
  266. Extension->CharsInInterruptBuffer) {
  267. // However if we are already holding we don't want
  268. // to turn it back on unless we exceed the Xon
  269. // limit.
  270. if (Extension->RXHolding & CYZ_RX_RTS) {
  271. // We can assume that its RTS line is already low.
  272. if (Extension->CharsInInterruptBuffer >
  273. (ULONG)New.XonLimit) {
  274. CyzDbgPrintEx(CYZFLOW, "Removing rts block of "
  275. "reception for Port%d Pci%d\n",
  276. Extension->PortIndex+1,Extension->PciSlot);
  277. Extension->RXHolding &= ~CYZ_RX_RTS;
  278. #ifndef FIRMWARE_HANDSHAKE
  279. CyzSetRTS(Extension);
  280. #endif
  281. }
  282. } else {
  283. #ifndef FIRMWARE_HANDSHAKE
  284. CyzSetRTS(Extension);
  285. #endif
  286. }
  287. } else {
  288. CyzDbgPrintEx(CYZFLOW, "Setting rts block of reception for "
  289. "Port%d Pci%d\n",
  290. Extension->PortIndex+1,Extension->PciSlot);
  291. Extension->RXHolding |= CYZ_RX_RTS;
  292. #ifndef FIRMWARE_HANDSHAKE
  293. CyzClrRTS(Extension);
  294. #endif
  295. }
  296. } else if ((New.FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_CONTROL) {
  297. #ifdef FIRMWARE_HANDSHAKE
  298. hw_flow = CYZ_READ_ULONG(&ch_ctrl->hw_flow);
  299. hw_flow &= ~C_RS_RTS;
  300. CYZ_WRITE_ULONG(&ch_ctrl->hw_flow,hw_flow);
  301. #endif
  302. // Note that if we aren't currently doing rts flow control then
  303. // we MIGHT have been. So even if we aren't currently doing
  304. // RTS flow control, we should still check if RX is holding
  305. // because of RTS. If it is, then we should clear the holding
  306. // of this bit.
  307. if (Extension->RXHolding & CYZ_RX_RTS) {
  308. CyzDbgPrintEx(CYZFLOW, "Clearing rts block of reception for "
  309. "Port%d Pci%d\n",
  310. Extension->PortIndex+1,Extension->PciSlot);
  311. Extension->RXHolding &= ~CYZ_RX_RTS;
  312. }
  313. CyzSetRTS(Extension);
  314. } else if((New.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) {
  315. // We first need to check whether reception is being held
  316. // up because of previous RTS flow control. If it is then
  317. // we should clear that reason in the RXHolding mask.
  318. if (Extension->RXHolding & CYZ_RX_RTS) {
  319. CyzDbgPrintEx(CYZFLOW, "TOGGLE Clearing rts block of "
  320. "reception for Port%d Pci%d\n",
  321. Extension->PortIndex+1,Extension->PciSlot);
  322. Extension->RXHolding &= ~CYZ_RX_RTS;
  323. }
  324. // We have to place the rts value into the Extension
  325. // now so that the code that tests whether the
  326. // rts line should be lowered will find that we
  327. // are "still" doing transmit toggling. The code
  328. // for lowering can be invoked later by a timer so
  329. // it has to test whether it still needs to do its
  330. // work.
  331. Extension->HandFlow.FlowReplace &= ~SERIAL_RTS_MASK;
  332. Extension->HandFlow.FlowReplace |= SERIAL_TRANSMIT_TOGGLE;
  333. // The order of the tests is very important below.
  334. // If there is a break then we should turn on the RTS.
  335. // If there isn't a break but there are characters in
  336. // the hardware, then turn on the RTS.
  337. // If there are writes pending that aren't being held
  338. // up, then turn on the RTS.
  339. if ((Extension->TXHolding & CYZ_TX_BREAK) ||
  340. (CyzAmountInTxBuffer(Extension)) ||
  341. (Extension->CurrentWriteIrp || Extension->TransmitImmediate ||
  342. (!IsListEmpty(&Extension->WriteQueue)) &&
  343. (!Extension->TXHolding))) {
  344. CyzSetRTS(Extension);
  345. } else {
  346. // This routine will check to see if it is time
  347. // to lower the RTS because of transmit toggle
  348. // being on. If it is ok to lower it, it will,
  349. // if it isn't ok, it will schedule things so
  350. // that it will get lowered later.
  351. Extension->CountOfTryingToLowerRTS++;
  352. CyzPerhapsLowerRTS(Extension);
  353. }
  354. } else {
  355. // The end result here will be that RTS is cleared.
  356. //
  357. // We first need to check whether reception is being held
  358. // up because of previous RTS flow control. If it is then
  359. // we should clear that reason in the RXHolding mask.
  360. if (Extension->RXHolding & CYZ_RX_RTS) {
  361. CyzDbgPrintEx(CYZFLOW, "Clearing rts block of reception for"
  362. " Port%d Pci%d\n",
  363. Extension->PortIndex+1,Extension->PciSlot);
  364. Extension->RXHolding &= ~CYZ_RX_RTS;
  365. }
  366. CyzClrRTS(Extension);
  367. }
  368. }
  369. // We now take care of automatic receive flow control.
  370. // We only do work if things have changed.
  371. if ((!Extension->DeviceIsOpened) ||
  372. ((Extension->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) !=
  373. (New.FlowReplace & SERIAL_AUTO_RECEIVE))) {
  374. if (New.FlowReplace & SERIAL_AUTO_RECEIVE) {
  375. // We wouldn't be here if it had been on before.
  376. //
  377. // We should check to see whether we exceed the turn
  378. // off limits.
  379. //
  380. // Note that since we are following the OS/2 flow
  381. // control rules we will never send an xon if
  382. // when enabling xon/xoff flow control we discover that
  383. // we could receive characters but we are held up do
  384. // to a previous Xoff.
  385. if ((Extension->BufferSize - New.XoffLimit) <=
  386. Extension->CharsInInterruptBuffer) {
  387. // Cause the Xoff to be sent.
  388. Extension->RXHolding |= CYZ_RX_XOFF;
  389. CyzProdXonXoff(Extension,FALSE);
  390. }
  391. } else {
  392. // The app has disabled automatic receive flow control.
  393. //
  394. // If transmission was being held up because of
  395. // an automatic receive Xoff, then we should
  396. // cause an Xon to be sent.
  397. if (Extension->RXHolding & CYZ_RX_XOFF) {
  398. Extension->RXHolding &= ~CYZ_RX_XOFF;
  399. // Cause the Xon to be sent.
  400. CyzProdXonXoff(Extension,TRUE);
  401. }
  402. }
  403. }
  404. // We now take care of automatic transmit flow control.
  405. // We only do work if things have changed.
  406. if ((!Extension->DeviceIsOpened) ||
  407. ((Extension->HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT) !=
  408. (New.FlowReplace & SERIAL_AUTO_TRANSMIT))) {
  409. if (New.FlowReplace & SERIAL_AUTO_TRANSMIT) {
  410. #if 0
  411. // Let's enable flow control at firmware level. The driver
  412. // is causing overflow in the remote devices.
  413. sw_flow = CYZ_READ_ULONG(&ch_ctrl->sw_flow);
  414. sw_flow |= C_FL_OXX;
  415. CYZ_WRITE_ULONG(&ch_ctrl->sw_flow,sw_flow);
  416. #endif
  417. // We wouldn't be here if it had been on before.
  418. //
  419. // There is some belief that if autotransmit
  420. // was just enabled, I should go look in what we
  421. // already received, and if we find the xoff character
  422. // then we should stop transmitting. I think this
  423. // is an application bug. For now we just care about
  424. // what we see in the future.
  425. ;
  426. } else {
  427. // The app has disabled automatic transmit flow control.
  428. //
  429. // If transmission was being held up because of
  430. // an automatic transmit Xoff, then we should
  431. // cause an Xon to be sent.
  432. #if 0
  433. // Disabling flow control at firmware level.
  434. sw_flow = CYZ_READ_ULONG(&ch_ctrl->sw_flow);
  435. sw_flow &= ~C_FL_OXX;
  436. CYZ_WRITE_ULONG(&ch_ctrl->sw_flow,sw_flow);
  437. #endif
  438. if (Extension->TXHolding & CYZ_TX_XOFF) {
  439. Extension->TXHolding &= ~CYZ_TX_XOFF;
  440. // Cause the Xon to be sent.
  441. CyzProdXonXoff(Extension,TRUE);
  442. }
  443. }
  444. }
  445. // For Cyclades-Z, we set the SERIAL_CTS_HANDSHAKE to be done by the
  446. // firmware.
  447. if ((!Extension->DeviceIsOpened) ||
  448. ((Extension->HandFlow.ControlHandShake & SERIAL_OUT_HANDSHAKEMASK) !=
  449. (New.ControlHandShake & SERIAL_OUT_HANDSHAKEMASK))) {
  450. if (New.ControlHandShake & SERIAL_CTS_HANDSHAKE) {
  451. hw_flow = CYZ_READ_ULONG(&ch_ctrl->hw_flow);
  452. hw_flow |= C_RS_CTS;
  453. CYZ_WRITE_ULONG(&ch_ctrl->hw_flow,hw_flow);
  454. } else {
  455. hw_flow = CYZ_READ_ULONG(&ch_ctrl->hw_flow);
  456. hw_flow &= ~C_RS_CTS;
  457. CYZ_WRITE_ULONG(&ch_ctrl->hw_flow,hw_flow);
  458. }
  459. if (New.ControlHandShake & SERIAL_DSR_HANDSHAKE) {
  460. hw_flow = CYZ_READ_ULONG(&ch_ctrl->hw_flow);
  461. hw_flow |= C_RS_DSR;
  462. CYZ_WRITE_ULONG(&ch_ctrl->hw_flow,hw_flow);
  463. } else {
  464. hw_flow = CYZ_READ_ULONG(&ch_ctrl->hw_flow);
  465. hw_flow &= ~C_RS_DSR;
  466. CYZ_WRITE_ULONG(&ch_ctrl->hw_flow,hw_flow);
  467. }
  468. if (New.ControlHandShake & SERIAL_DCD_HANDSHAKE) {
  469. hw_flow = CYZ_READ_ULONG(&ch_ctrl->hw_flow);
  470. hw_flow |= C_RS_DCD;
  471. CYZ_WRITE_ULONG(&ch_ctrl->hw_flow,hw_flow);
  472. } else {
  473. hw_flow = CYZ_READ_ULONG(&ch_ctrl->hw_flow);
  474. hw_flow &= ~C_RS_DCD;
  475. CYZ_WRITE_ULONG(&ch_ctrl->hw_flow,hw_flow);
  476. }
  477. }
  478. CyzIssueCmd(Extension,C_CM_IOCTLW,0L,FALSE);
  479. // At this point we can simply make sure that entire
  480. // handflow structure in the extension is updated.
  481. Extension->HandFlow = New;
  482. return FALSE;
  483. }
  484. BOOLEAN
  485. CyzSetHandFlow(
  486. IN PVOID Context
  487. )
  488. /*--------------------------------------------------------------------------
  489. CyzSetHandFlow()
  490. Routine Description: This routine is used to set the handshake and
  491. control flow in the device extension.
  492. Arguments:
  493. Context - Pointer to a structure that contains a pointer to the device
  494. extension and a pointer to a handflow structure.
  495. Return Value: This routine always returns FALSE.
  496. --------------------------------------------------------------------------*/
  497. {
  498. PCYZ_IOCTL_SYNC S = Context;
  499. PCYZ_DEVICE_EXTENSION Extension = S->Extension;
  500. PSERIAL_HANDFLOW HandFlow = S->Data;
  501. CyzSetupNewHandFlow(Extension,HandFlow);
  502. CyzHandleModemUpdate(Extension,FALSE,0);
  503. return FALSE;
  504. }
  505. BOOLEAN
  506. CyzTurnOnBreak(
  507. IN PVOID Context
  508. )
  509. /*--------------------------------------------------------------------------
  510. CyzTurnOnBreak()
  511. Routine Description: This routine will turn on break in the
  512. hardware and record the fact the break is on, in the extension
  513. variable that holds reasons that transmission is stopped.
  514. Arguments:
  515. Context - Really a pointer to the device extension.
  516. Return Value: This routine always returns FALSE.
  517. --------------------------------------------------------------------------*/
  518. {
  519. PCYZ_DEVICE_EXTENSION Extension = Context;
  520. UCHAR OldLineControl;
  521. if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
  522. SERIAL_TRANSMIT_TOGGLE) {
  523. CyzSetRTS(Extension);
  524. }
  525. CyzIssueCmd(Extension,C_CM_SET_BREAK,0L,FALSE); // This will set break.
  526. // CyzIssueCmd(Extension,C_CM_SENDBRK,0L); This will set and reset break.
  527. Extension->TXHolding |= CYZ_TX_BREAK;
  528. return FALSE;
  529. }
  530. BOOLEAN
  531. CyzTurnOffBreak(
  532. IN PVOID Context
  533. )
  534. /*--------------------------------------------------------------------------
  535. CyzturnOffBreak()
  536. Routine Description: This routine will turn off break in the
  537. hardware and record the fact the break is off, in the extension
  538. variable that holds reasons that transmission is stopped.
  539. Arguments:
  540. Context - Really a pointer to the device extension.
  541. Return Value: This routine always returns FALSE.
  542. --------------------------------------------------------------------------*/
  543. {
  544. PCYZ_DEVICE_EXTENSION Extension = Context;
  545. UCHAR OldLineControl;
  546. if (Extension->TXHolding & CYZ_TX_BREAK) {
  547. //
  548. // We actually have a good reason for testing if transmission
  549. // is holding instead of blindly clearing the bit.
  550. //
  551. // If transmission actually was holding and the result of
  552. // clearing the bit is that we should restart transmission
  553. // then we will poke the interrupt enable bit, which will
  554. // cause an actual interrupt and transmission will then
  555. // restart on its own.
  556. //
  557. // If transmission wasn't holding and we poked the bit
  558. // then we would interrupt before a character actually made
  559. // it out and we could end up over writing a character in
  560. // the transmission hardware.
  561. CyzIssueCmd(Extension,C_CM_CLR_BREAK,0L,FALSE);
  562. Extension->TXHolding &= ~CYZ_TX_BREAK;
  563. if (!Extension->TXHolding &&
  564. (Extension->TransmitImmediate ||
  565. Extension->WriteLength) &&
  566. Extension->HoldingEmpty) {
  567. #ifndef POLL
  568. CyzTxStart(Extension);
  569. #endif
  570. } else {
  571. //
  572. // The following routine will lower the rts if we
  573. // are doing transmit toggleing and there is no
  574. // reason to keep it up.
  575. //
  576. Extension->CountOfTryingToLowerRTS++;
  577. CyzPerhapsLowerRTS(Extension);
  578. }
  579. }
  580. return FALSE;
  581. }
  582. BOOLEAN
  583. CyzPretendXoff(
  584. IN PVOID Context
  585. )
  586. /*--------------------------------------------------------------------------
  587. CyzPretendXoff()
  588. Routine Description: This routine is used to process the Ioctl that
  589. request the driver to act as if an Xoff was received. Even if the
  590. driver does not have automatic Xoff/Xon flowcontrol - This still will
  591. stop the transmission. This is the OS/2 behavior and is not well
  592. specified for Windows. Therefore we adopt the OS/2 behavior.
  593. Note: If the driver does not have automatic Xoff/Xon enabled
  594. then the only way to restart transmission is for the
  595. application to request we "act" as if we saw the xon.
  596. Arguments:
  597. Context - pointer to the device extension.
  598. Return Value: This routine always returns FALSE.
  599. --------------------------------------------------------------------------*/
  600. {
  601. PCYZ_DEVICE_EXTENSION Extension = Context;
  602. Extension->TXHolding |= CYZ_TX_XOFF;
  603. if((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
  604. SERIAL_TRANSMIT_TOGGLE) {
  605. CyzInsertQueueDpc(
  606. &Extension->StartTimerLowerRTSDpc,
  607. NULL,
  608. NULL,
  609. Extension
  610. )?Extension->CountOfTryingToLowerRTS++:0;
  611. }
  612. return FALSE;
  613. }
  614. BOOLEAN
  615. CyzPretendXon(
  616. IN PVOID Context
  617. )
  618. /*--------------------------------------------------------------------------
  619. CyzPretendXon()
  620. Routine Description: This routine is used to process the Ioctl that
  621. request the driver to act as if an Xon was received.
  622. Note: If the driver does not have automatic Xoff/Xon enabled
  623. then the only way to restart transmission is for the
  624. application to request we "act" as if we saw the xon.
  625. Arguments:
  626. Context - pointer to the device extension.
  627. Return Value:
  628. This routine always returns FALSE.
  629. --------------------------------------------------------------------------*/
  630. {
  631. PCYZ_DEVICE_EXTENSION Extension = Context;
  632. if (Extension->TXHolding) {
  633. // We actually have a good reason for testing if transmission
  634. // is holding instead of blindly clearing the bit.
  635. //
  636. // If transmission actually was holding and the result of
  637. // clearing the bit is that we should restart transmission
  638. // then we will poke the interrupt enable bit, which will
  639. // cause an actual interrupt and transmission will then
  640. // restart on its own.
  641. //
  642. // If transmission wasn't holding and we poked the bit
  643. // then we would interrupt before a character actually made
  644. // it out and we could end up over writing a character in
  645. // the transmission hardware.
  646. Extension->TXHolding &= ~CYZ_TX_XOFF;
  647. //Removed at 02/07/00 by Fanny. Polling routine will do the transmission.
  648. // if (!Extension->TXHolding &&
  649. // (Extension->TransmitImmediate ||
  650. // Extension->WriteLength) &&
  651. // Extension->HoldingEmpty) {
  652. //
  653. // CyzTxStart(Extension);
  654. // }
  655. }
  656. return FALSE;
  657. }
  658. VOID
  659. CyzHandleReducedIntBuffer(
  660. IN PCYZ_DEVICE_EXTENSION Extension
  661. )
  662. /*--------------------------------------------------------------------------
  663. CyzHandleReducedIntBuffer()
  664. Routine Description: This routine is called to handle a reduction in
  665. the number of characters in the interrupt (typeahead) buffer. It
  666. will check the current output flow control and re-enable transmission
  667. as needed.
  668. NOTE: This routine assumes that it is working at interrupt level.
  669. Arguments:
  670. Extension - A pointer to the device extension.
  671. Return Value: None.
  672. --------------------------------------------------------------------------*/
  673. {
  674. #ifndef POLL
  675. struct BUF_CTRL *buf_ctrl = Extension->BufCtrl;
  676. ULONG rx_threshold = CYZ_READ_ULONG(&buf_ctrl->rx_threshold);
  677. if (CyzAmountInRxBuffer(Extension) > rx_threshold) {
  678. #if DBG
  679. DbgPrint("Above threshold\n");
  680. #endif
  681. CyzRx(Extension);
  682. }
  683. #endif
  684. //
  685. // If we are doing receive side flow control and we are
  686. // currently "holding" then because we've emptied out
  687. // some characters from the interrupt buffer we need to
  688. // see if we can "re-enable" reception.
  689. //
  690. if (Extension->RXHolding) {
  691. //LOGENTRY(LOG_MISC, ZSIG_HANDLE_REDUCED_BUFFER,
  692. // Extension->PortIndex+1,
  693. // Extension->RXHolding,
  694. // 0);
  695. if (Extension->CharsInInterruptBuffer <=
  696. (ULONG)Extension->HandFlow.XonLimit) {
  697. if (Extension->RXHolding & CYZ_RX_DTR) {
  698. Extension->RXHolding &= ~CYZ_RX_DTR;
  699. CyzSetDTR(Extension);
  700. }
  701. if (Extension->RXHolding & CYZ_RX_RTS) {
  702. Extension->RXHolding &= ~CYZ_RX_RTS;
  703. CyzSetRTS(Extension);
  704. }
  705. if (Extension->RXHolding & CYZ_RX_XOFF) {
  706. CyzProdXonXoff(Extension,TRUE );
  707. }
  708. }
  709. }
  710. }
  711. VOID
  712. CyzProdXonXoff(
  713. IN PCYZ_DEVICE_EXTENSION Extension,
  714. IN BOOLEAN SendXon
  715. )
  716. /*--------------------------------------------------------------------------
  717. CyzProdXonXoff()
  718. Routine Description: This routine will set up the SendXxxxChar
  719. variables if necessary and determine if we are going to be interrupting
  720. because of current transmission state. It will cause an
  721. interrupt to occur if neccessary, to send the xon/xoff char.
  722. NOTE: This routine assumes that it is called at interrupt level.
  723. Arguments:
  724. Extension - A pointer to the serial device extension.
  725. SendXon - If a character is to be send, this indicates whether
  726. it should be an Xon or an Xoff.
  727. Return Value: None.
  728. --------------------------------------------------------------------------*/
  729. {
  730. //CHANGED FOR MODEMSHARE TEST CASES 6 (SMALL_THREAD_TXFER_CASE), 41 (MEDIUM_THREAD_TXFER_CASE)
  731. //AND 67 (MEDIUM_NESTED_OVERLAPPED_THREAD_TRANSFER_CASE). WE WILL SEND XON/XOFF DURING
  732. //NEXT POLLING ROUTINE TO GIVE TIME FOR THE HARDWARE FLOW CONTROL TO BE ENABLED.
  733. //
  734. // if (SendXon) {
  735. // CyzSendXon(Extension);
  736. // } else {
  737. // CyzSendXoff(Extension);
  738. // }
  739. if (SendXon) {
  740. Extension->SendXonChar = TRUE;
  741. Extension->SendXoffChar = FALSE;
  742. } else {
  743. Extension->SendXonChar = FALSE;
  744. Extension->SendXoffChar = TRUE;
  745. }
  746. }
  747. ULONG
  748. CyzHandleModemUpdate(
  749. IN PCYZ_DEVICE_EXTENSION Extension,
  750. IN BOOLEAN DoingTX,
  751. IN ULONG Reason
  752. )
  753. /*--------------------------------------------------------------------------
  754. CyzHandleModemUpdate()
  755. Routine Description: check on the modem status, and handle any
  756. appropriate event notification as well as any flow control appropriate
  757. to modem status lines.
  758. Arguments:
  759. Extension - A pointer to the serial device extension.
  760. DoingTX - This boolean is used to indicate that this call
  761. came from the transmit processing code. If this
  762. is true then there is no need to cause a new interrupt
  763. since the code will be trying to send the next
  764. character as soon as this call finishes.
  765. Reason - Value copied from loc_doorbell.
  766. Return Value: This returns the old value of the modem status register
  767. --------------------------------------------------------------------------*/
  768. {
  769. ULONG OldTXHolding = Extension->TXHolding;
  770. UCHAR ModemStatus = 0;
  771. ULONG msvr; // ,msvrxor;
  772. struct CH_CTRL *ch_ctrl;
  773. ch_ctrl = Extension->ChCtrl;
  774. msvr = CYZ_READ_ULONG(&ch_ctrl->rs_status);
  775. //Removed. Let's try another thing for Worldgroup.
  776. //if (Extension->DCDFlag){
  777. // msvr &= ~C_RS_DCD;
  778. // msvr |= Extension->DCDstatus;
  779. // Extension->DCDFlag = 0;
  780. //}
  781. msvr &= ~C_RS_DCD;
  782. msvr |= Extension->DCDstatus;
  783. if(msvr & C_RS_CTS) ModemStatus |= SERIAL_MSR_CTS;
  784. if(msvr & C_RS_DSR) ModemStatus |= SERIAL_MSR_DSR;
  785. if(msvr & C_RS_RI) ModemStatus |= SERIAL_MSR_RI;
  786. if(msvr & C_RS_DCD) ModemStatus |= SERIAL_MSR_DCD;
  787. if(Reason == C_CM_MCTS) ModemStatus |= SERIAL_MSR_DCTS;
  788. if(Reason == C_CM_MDSR) ModemStatus |= SERIAL_MSR_DDSR;
  789. if(Reason == C_CM_MRI) ModemStatus |= SERIAL_MSR_TERI;
  790. if(Reason == C_CM_MDCD) ModemStatus |= SERIAL_MSR_DDCD;
  791. #if 0
  792. if(Extension->LieRIDSR == TRUE) { // we have to lie...
  793. ModemStatus |= SERIAL_MSR_DSR; // DSR always on
  794. ModemStatus &= ~(SERIAL_MSR_RI); // RI always off
  795. ModemStatus &= ~(SERIAL_MSR_DDSR | SERIAL_MSR_TERI);
  796. }
  797. #endif
  798. // If we are placing the modem status into the data stream
  799. // on every change, we should do it now.
  800. if (Extension->EscapeChar) {
  801. if (ModemStatus & (SERIAL_MSR_DCTS |
  802. SERIAL_MSR_DDSR |
  803. SERIAL_MSR_TERI |
  804. SERIAL_MSR_DDCD)) {
  805. CyzPutChar(Extension,Extension->EscapeChar);
  806. CyzPutChar(Extension,SERIAL_LSRMST_MST);
  807. CyzPutChar(Extension,ModemStatus);
  808. }
  809. }
  810. // Take care of input flow control based on sensitivity
  811. // to the DSR. This is done so that the application won't
  812. // see spurious data generated by odd devices.
  813. //
  814. // Basically, if we are doing dsr sensitivity then the
  815. // driver should only accept data when the dsr bit is set.
  816. if (Extension->HandFlow.ControlHandShake & SERIAL_DSR_SENSITIVITY) {
  817. if (ModemStatus & SERIAL_MSR_DSR) {
  818. Extension->RXHolding &= ~CYZ_RX_DSR;
  819. } else {
  820. Extension->RXHolding |= CYZ_RX_DSR;
  821. }
  822. } else {
  823. Extension->RXHolding &= ~CYZ_RX_DSR;
  824. }
  825. // Check to see if we have a wait pending on the modem status events.
  826. // If we do then we schedule a dpc to satisfy that wait.
  827. if (Extension->IsrWaitMask) {
  828. if((Extension->IsrWaitMask&SERIAL_EV_CTS)&&(ModemStatus&SERIAL_MSR_DCTS)) {
  829. Extension->HistoryMask |= SERIAL_EV_CTS;
  830. }
  831. if((Extension->IsrWaitMask&SERIAL_EV_DSR)&&(ModemStatus&SERIAL_MSR_DDSR)) {
  832. Extension->HistoryMask |= SERIAL_EV_DSR;
  833. }
  834. if((Extension->IsrWaitMask&SERIAL_EV_RING)&&(ModemStatus&SERIAL_MSR_TERI)) {
  835. Extension->HistoryMask |= SERIAL_EV_RING;
  836. }
  837. if((Extension->IsrWaitMask&SERIAL_EV_RLSD)&&(ModemStatus&SERIAL_MSR_DDCD)) {
  838. Extension->HistoryMask |= SERIAL_EV_RLSD;
  839. }
  840. if(Extension->IrpMaskLocation && Extension->HistoryMask) {
  841. *Extension->IrpMaskLocation = Extension->HistoryMask;
  842. Extension->IrpMaskLocation = NULL;
  843. Extension->HistoryMask = 0;
  844. Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
  845. CyzInsertQueueDpc(&Extension->CommWaitDpc,NULL,NULL,Extension);
  846. }
  847. }
  848. // If the app has modem line flow control then
  849. // we check to see if we have to hold up transmission.
  850. if (Extension->HandFlow.ControlHandShake & SERIAL_OUT_HANDSHAKEMASK) {
  851. if (Extension->HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE) {
  852. if (ModemStatus & SERIAL_MSR_CTS) {
  853. Extension->TXHolding &= ~CYZ_TX_CTS;
  854. } else {
  855. Extension->TXHolding |= CYZ_TX_CTS;
  856. }
  857. } else {
  858. Extension->TXHolding &= ~CYZ_TX_CTS;
  859. }
  860. if (Extension->HandFlow.ControlHandShake & SERIAL_DSR_HANDSHAKE) {
  861. if (ModemStatus & SERIAL_MSR_DSR) {
  862. Extension->TXHolding &= ~CYZ_TX_DSR;
  863. } else {
  864. Extension->TXHolding |= CYZ_TX_DSR;
  865. }
  866. } else {
  867. Extension->TXHolding &= ~CYZ_TX_DSR;
  868. }
  869. if (Extension->HandFlow.ControlHandShake & SERIAL_DCD_HANDSHAKE) {
  870. if (ModemStatus & SERIAL_MSR_DCD) {
  871. Extension->TXHolding &= ~CYZ_TX_DCD;
  872. } else {
  873. Extension->TXHolding |= CYZ_TX_DCD;
  874. }
  875. } else {
  876. Extension->TXHolding &= ~CYZ_TX_DCD;
  877. }
  878. // If we hadn't been holding, and now we are then
  879. // queue off a dpc that will lower the RTS line
  880. // if we are doing transmit toggling.
  881. if (!OldTXHolding && Extension->TXHolding &&
  882. ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
  883. SERIAL_TRANSMIT_TOGGLE)) {
  884. CyzInsertQueueDpc(
  885. &Extension->StartTimerLowerRTSDpc,
  886. NULL,
  887. NULL,
  888. Extension
  889. )?Extension->CountOfTryingToLowerRTS++:0;
  890. }
  891. //Removed at 02/07/00 by Fanny. Polling routine will do the transmission.
  892. // // We've done any adjusting that needed to be
  893. // // done to the holding mask given updates
  894. // // to the modem status. If the Holding mask
  895. // // is clear (and it wasn't clear to start)
  896. // // and we have "write" work to do set things
  897. // // up so that the transmission code gets invoked.
  898. //
  899. // if (!DoingTX && OldTXHolding && !Extension->TXHolding) {
  900. // if (!Extension->TXHolding &&
  901. // (Extension->TransmitImmediate ||
  902. // Extension->WriteLength) &&
  903. // Extension->HoldingEmpty) {
  904. //
  905. // CyzTxStart(Extension);
  906. // }
  907. // }
  908. } else {
  909. // We need to check if transmission is holding
  910. // up because of modem status lines. What
  911. // could have occured is that for some strange
  912. // reason, the app has asked that we no longer
  913. // stop doing output flow control based on
  914. // the modem status lines. If however, we
  915. // *had* been held up because of the status lines
  916. // then we need to clear up those reasons.
  917. if (Extension->TXHolding & (CYZ_TX_DCD | CYZ_TX_DSR | CYZ_TX_CTS)) {
  918. Extension->TXHolding &= ~(CYZ_TX_DCD | CYZ_TX_DSR | CYZ_TX_CTS);
  919. if (!DoingTX && OldTXHolding && !Extension->TXHolding) {
  920. if (!Extension->TXHolding &&
  921. (Extension->TransmitImmediate ||
  922. Extension->WriteLength) &&
  923. Extension->HoldingEmpty) {
  924. CyzTxStart(Extension);
  925. }
  926. }
  927. }
  928. }
  929. return ((ULONG)ModemStatus);
  930. }
  931. BOOLEAN
  932. CyzPerhapsLowerRTS(
  933. IN PVOID Context
  934. )
  935. /*--------------------------------------------------------------------------
  936. CyzPerhapsLowerRTS()
  937. Routine Description: This routine checks that the software reasons for
  938. lowering the RTS lines are present. If so, it will then cause the
  939. line status register to be read (and any needed processing
  940. implied by the status register to be done), and if the shift register
  941. is empty it will lower the line. If the shift register isn't empty,
  942. this routine will queue off a dpc that will start a timer, that will
  943. basically call us back to try again.
  944. NOTE: This routine assumes that it is called at interrupt level.
  945. Arguments:
  946. Context - pointer to the device extension.
  947. Return Value: Always FALSE.
  948. --------------------------------------------------------------------------*/
  949. {
  950. PCYZ_DEVICE_EXTENSION Extension = Context;
  951. // We first need to test if we are actually still doing
  952. // transmit toggle flow control. If we aren't then
  953. // we have no reason to try be here.
  954. if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
  955. SERIAL_TRANSMIT_TOGGLE) {
  956. // The order of the tests is very important below.
  957. // If there is a break then we should leave on the RTS,
  958. // because when the break is turned off, it will submit
  959. // the code to shut down the RTS.
  960. // If there are writes pending that aren't being held
  961. // up, then leave on the RTS, because the end of the write
  962. // code will cause this code to be reinvoked. If the writes
  963. // are being held up, its ok to lower the RTS because the
  964. // upon trying to write the first character after transmission
  965. // is restarted, we will raise the RTS line.
  966. if ((Extension->TXHolding & CYZ_TX_BREAK) ||
  967. (Extension->CurrentWriteIrp || Extension->TransmitImmediate ||
  968. (!IsListEmpty(&Extension->WriteQueue)) &&
  969. (!Extension->TXHolding))) {
  970. NOTHING;
  971. } else {
  972. // Looks good so far. Call the line status check and processing
  973. // code, it will return the "current" line status value. If
  974. // the holding and shift register are clear, lower the RTS line,
  975. // if they aren't clear, queue of a dpc that will cause a timer
  976. // to reinvoke us later. We do this code here because no one
  977. // but this routine cares about the characters in the hardware,
  978. // so no routine by this routine will bother invoking to test
  979. // if the hardware is empty.
  980. if (CyzAmountInTxBuffer(Extension)){
  981. #if 0
  982. if ((CyzProcessLSR(Extension) & (CYZ_LSR_THRE | CYZ_LSR_TEMT)) !=
  983. (CYZ_LSR_THRE | CYZ_LSR_TEMT))
  984. #endif
  985. // Well it's not empty, try again later.
  986. CyzInsertQueueDpc(
  987. &Extension->StartTimerLowerRTSDpc,
  988. NULL,
  989. NULL,
  990. Extension
  991. )?Extension->CountOfTryingToLowerRTS++:0;
  992. } else {
  993. // Nothing in the hardware, Lower the RTS.
  994. CyzClrRTS(Extension);
  995. }
  996. }
  997. }
  998. // We decement the counter to indicate that we've reached
  999. // the end of the execution path that is trying to push
  1000. // down the RTS line.
  1001. Extension->CountOfTryingToLowerRTS--;
  1002. return FALSE;
  1003. }
  1004. VOID
  1005. CyzStartTimerLowerRTS(
  1006. IN PKDPC Dpc,
  1007. IN PVOID DeferredContext,
  1008. IN PVOID SystemContext1,
  1009. IN PVOID SystemContext2
  1010. )
  1011. /*--------------------------------------------------------------------------
  1012. CyzStartTimerLowerRTS()
  1013. Routine Description: This routine starts a timer that when it expires
  1014. will start a dpc that will check if it can lower the rts line because
  1015. there are no characters in the hardware.
  1016. Arguments:
  1017. Dpc - Not Used.
  1018. DeferredContext - points to the device extension.
  1019. SystemContext1 - Not Used.
  1020. SystemContext2 - Not Used.
  1021. Return Value: None.
  1022. --------------------------------------------------------------------------*/
  1023. {
  1024. PCYZ_DEVICE_EXTENSION Extension = DeferredContext;
  1025. LARGE_INTEGER CharTime;
  1026. ULONG AmountBeingTx;
  1027. LARGE_INTEGER TotalTime;
  1028. KIRQL OldIrql;
  1029. #ifdef POLL
  1030. KIRQL pollIrql;
  1031. #endif
  1032. UNREFERENCED_PARAMETER(Dpc);
  1033. UNREFERENCED_PARAMETER(SystemContext1);
  1034. UNREFERENCED_PARAMETER(SystemContext2);
  1035. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzStartTimerLowerRTS(%X)\n",
  1036. Extension);
  1037. // Take out the lock to prevent the line control
  1038. // from changing out from under us while we calculate
  1039. // a character time.
  1040. KeAcquireSpinLock(&Extension->ControlLock,&OldIrql);
  1041. CharTime = CyzGetCharTime(Extension);
  1042. KeReleaseSpinLock(&Extension->ControlLock,OldIrql);
  1043. CharTime.QuadPart = -CharTime.QuadPart;
  1044. AmountBeingTx = CyzAmountInTxBuffer(Extension);
  1045. TotalTime.QuadPart = AmountBeingTx*CharTime.QuadPart;
  1046. if (CyzSetTimer(
  1047. &Extension->LowerRTSTimer,
  1048. TotalTime,
  1049. &Extension->PerhapsLowerRTSDpc,
  1050. Extension
  1051. )) {
  1052. // The timer was already in the timer queue. This implies
  1053. // that one path of execution that was trying to lower
  1054. // the RTS has "died". Synchronize with the ISR so that
  1055. // we can lower the count.
  1056. #ifdef POLL
  1057. KeAcquireSpinLock(&Extension->PollLock,&pollIrql);
  1058. CyzDecrementRTSCounter(Extension);
  1059. KeReleaseSpinLock(&Extension->PollLock,pollIrql);
  1060. #else
  1061. KeSynchronizeExecution(
  1062. Extension->Interrupt,
  1063. CyzDecrementRTSCounter,
  1064. Extension
  1065. );
  1066. #endif
  1067. }
  1068. CyzDpcEpilogue(Extension, Dpc);
  1069. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzStartTimerLowerRTS\n");
  1070. }
  1071. VOID
  1072. CyzInvokePerhapsLowerRTS(
  1073. IN PKDPC Dpc,
  1074. IN PVOID DeferredContext,
  1075. IN PVOID SystemContext1,
  1076. IN PVOID SystemContext2
  1077. )
  1078. /*--------------------------------------------------------------------------
  1079. CyzInvokePerhapsLowerRTS()
  1080. Routine Description: This dpc routine exists solely to call the code
  1081. that tests if the rts line should be lowered when TRANSMIT TOGGLE
  1082. flow control is being used.
  1083. Arguments:
  1084. Dpc - Not Used.
  1085. DeferredContext - points to the device extension.
  1086. SystemContext1 - Not Used.
  1087. SystemContext2 - Not Used.
  1088. Return Value: None.
  1089. --------------------------------------------------------------------------*/
  1090. {
  1091. PCYZ_DEVICE_EXTENSION Extension = DeferredContext;
  1092. KIRQL pollIrql;
  1093. UNREFERENCED_PARAMETER(Dpc);
  1094. UNREFERENCED_PARAMETER(SystemContext1);
  1095. UNREFERENCED_PARAMETER(SystemContext2);
  1096. #ifdef POLL
  1097. KeAcquireSpinLock(&Extension->PollLock,&pollIrql);
  1098. CyzPerhapsLowerRTS(Extension);
  1099. KeReleaseSpinLock(&Extension->PollLock,pollIrql);
  1100. #else
  1101. KeSynchronizeExecution(
  1102. Extension->Interrupt,
  1103. CyzPerhapsLowerRTS,
  1104. Extension
  1105. );
  1106. #endif
  1107. }
  1108. BOOLEAN
  1109. CyzDecrementRTSCounter(
  1110. IN PVOID Context
  1111. )
  1112. /*--------------------------------------------------------------------------
  1113. CyzDecrementRTSCounter()
  1114. Routine Description: This routine checks that the software reasons for
  1115. lowering the RTS lines are present. If so, it will then cause the
  1116. line status register to be read (and any needed processing implied by
  1117. the status register to be done), and if the shift register is empty it
  1118. will lower the line. If the shift register isn't empty, this routine
  1119. will queue off a dpc that will start a timer, that will basically call
  1120. us back to try again.
  1121. NOTE: This routine assumes that it is called at interrupt level.
  1122. Arguments:
  1123. Context - pointer to the device extension.
  1124. Return Value: Always FALSE.
  1125. --------------------------------------------------------------------------*/
  1126. {
  1127. PCYZ_DEVICE_EXTENSION Extension = Context;
  1128. Extension->CountOfTryingToLowerRTS--;
  1129. return FALSE;
  1130. }
  1131.