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.

1426 lines
49 KiB

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