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.

1159 lines
41 KiB

  1. /*--------------------------------------------------------------------------
  2. *
  3. * Copyright (C) Cyclades Corporation, 1996-2001.
  4. * All rights reserved.
  5. *
  6. * Cyclom-Y Port Driver
  7. *
  8. * This file: cyyintr.c
  9. *
  10. * Description: This module contains the code related to interrupt
  11. * handling 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. // FANNY: THIS WAS IN CYINIT.C. IT WILL PROBABLY DESAPPEAR FROM HERE TOO.
  31. //extern const unsigned long CyyCDOffset[];
  32. const unsigned long CyyCDOffset[] = { // CD1400 offsets within the board
  33. 0x00000000,0x00000400,0x00000800,0x00000C00,
  34. 0x00000200,0x00000600,0x00000A00,0x00000E00
  35. };
  36. //ADDED TO DEBUG_RTPR
  37. extern PDRIVER_OBJECT CyyDO;
  38. //END DEBUG_RTPR
  39. #ifdef ALLOC_PRAGMA
  40. //#pragma alloc_text(PAGESER,CyyIsr)
  41. //#pragma alloc_text(PAGESER,CyyPutChar)
  42. //#pragma alloc_text(PAGESER,CyyProcessLSR)
  43. //#pragma alloc_text(PAGESER,CyyTxStart)
  44. //#pragma alloc_text(PAGESER,CyySendXon)
  45. //#pragma alloc_text(PAGESER,CyySendXoff)
  46. #endif
  47. BOOLEAN
  48. CyyIsr(
  49. IN PKINTERRUPT InterruptObject,
  50. IN PVOID Context
  51. )
  52. /*--------------------------------------------------------------------------
  53. CyyIsr()
  54. Routine Description: This is the interrupt service routine for the
  55. Cyclom-Y Port driver.
  56. Arguments:
  57. InterruptObject - Pointer to interrupt object (not used).
  58. Context - Pointer to the device extension for this device.
  59. Return Value: This function will return TRUE if the serial port is
  60. the source of this interrupt, FALSE otherwise.
  61. --------------------------------------------------------------------------*/
  62. {
  63. PCYY_DISPATCH Dispatch = Context;
  64. PCYY_DEVICE_EXTENSION Extension;
  65. BOOLEAN ServicedAnInterrupt = FALSE;
  66. PUCHAR chip;
  67. PUCHAR mappedboard = NULL;
  68. ULONG bus = Dispatch->IsPci;
  69. unsigned char status, save_xir, save_car, x, rxchar=0;
  70. ULONG i,channel,chipindex,portindex;
  71. UCHAR misr;
  72. BOOLEAN thisChipInterrupted;
  73. PCYY_DEVICE_EXTENSION interlockedExtension[CYY_CHANNELS_PER_CHIP];
  74. UNREFERENCED_PARAMETER(InterruptObject);
  75. //DbgPrint("Isr>\n");
  76. // Loop polling all chips in the board
  77. for(portindex = 0 ; portindex < CYY_MAX_PORTS ;) {
  78. if (!(Extension=Dispatch->Extensions[portindex]) ||
  79. !(chip=Dispatch->Cd1400[portindex])) {
  80. portindex++;
  81. continue;
  82. }
  83. chipindex = portindex/4;
  84. mappedboard = Extension->BoardMemory;
  85. thisChipInterrupted = FALSE;
  86. interlockedExtension[0] = interlockedExtension[1]
  87. = interlockedExtension[2] = interlockedExtension[3] = 0;
  88. while ((status = CD1400_READ(chip,bus,SVRR)) != 0x00) {
  89. ServicedAnInterrupt = TRUE;
  90. thisChipInterrupted = TRUE;
  91. if (status & 0x01) {
  92. //Reception
  93. save_xir = CD1400_READ(chip,bus,RIR);
  94. channel = (ULONG) (save_xir & 0x03);
  95. save_car = CD1400_READ(chip,bus,CAR);
  96. CD1400_WRITE(chip,bus,CAR,save_xir);
  97. Extension = Dispatch->Extensions[channel + CYY_CHANNELS_PER_CHIP*chipindex];
  98. x = CD1400_READ(chip,bus,RIVR) & 0x07;
  99. if (Extension) {
  100. //
  101. // Apply lock so if close happens concurrently we don't miss the DPC
  102. // queueing
  103. //
  104. if (interlockedExtension[channel] == NULL) {
  105. interlockedExtension[channel] = Extension;
  106. InterlockedIncrement(&Extension->DpcCount);
  107. LOGENTRY(LOG_CNT, 'DpI3', 0, Extension->DpcCount, 0); // Added in bld 2128
  108. }
  109. if (x == 0x07) { // exception
  110. x = CD1400_READ(chip,bus,RDSR); // status
  111. CyyDbgPrintEx(DPFLTR_WARNING_LEVEL, "exception %x\n",x);
  112. if (Extension->DeviceIsOpened &&
  113. (Extension->PowerState == PowerDeviceD0)) {
  114. if (x & CYY_LSR_ERROR){
  115. BOOLEAN ProcessRxChar;
  116. if (!(x & CYY_LSR_OE)) {
  117. rxchar = CD1400_READ(chip,bus,RDSR); // error data
  118. }
  119. // TODO: SERIAL SAMPLE FOR W2000 HAS ADDED
  120. // CHECKING FOR EscapeChar TO BREAK TO RX LOOP
  121. // IN CASE OF ERROR.
  122. ProcessRxChar = CyyProcessLSR(Extension,x,rxchar);
  123. if (ProcessRxChar) {
  124. x = 1; // 1 character
  125. i = 0; // prepare for for(;;)
  126. goto Handle_rxchar;
  127. }
  128. } // end error handling
  129. } // end if DeviceIsOpened..
  130. } else { // good reception
  131. x = CD1400_READ(chip,bus,RDCR);
  132. if (Extension->DeviceIsOpened &&
  133. (Extension->PowerState == PowerDeviceD0)) {
  134. for(i = 0 ; i < x ; i++) { // read from FIFO
  135. rxchar = CD1400_READ(chip,bus,RDSR);
  136. Handle_rxchar:
  137. Extension->PerfStats.ReceivedCount++;
  138. Extension->WmiPerfData.ReceivedCount++;
  139. rxchar &= Extension->ValidDataMask;
  140. if (!rxchar && // NULL stripping
  141. (Extension->HandFlow.FlowReplace &
  142. SERIAL_NULL_STRIPPING)) {
  143. continue;
  144. }
  145. if((Extension->HandFlow.FlowReplace &
  146. SERIAL_AUTO_TRANSMIT) &&
  147. ((rxchar == Extension->SpecialChars.XonChar) ||
  148. (rxchar == Extension->SpecialChars.XoffChar))) {
  149. if (rxchar == Extension->SpecialChars.XoffChar) {
  150. Extension->TXHolding |= CYY_TX_XOFF;
  151. if ((Extension->HandFlow.FlowReplace &
  152. SERIAL_RTS_MASK) ==
  153. SERIAL_TRANSMIT_TOGGLE) {
  154. CyyInsertQueueDpc(
  155. &Extension->StartTimerLowerRTSDpc,
  156. NULL,
  157. NULL,
  158. Extension
  159. )?Extension->CountOfTryingToLowerRTS++:0;
  160. }
  161. } else {
  162. if (Extension->TXHolding & CYY_TX_XOFF) {
  163. Extension->TXHolding &= ~CYY_TX_XOFF;
  164. }
  165. }
  166. continue;
  167. }
  168. // Check to see if we should note the receive
  169. // character or special character event.
  170. if (Extension->IsrWaitMask) {
  171. if (Extension->IsrWaitMask & SERIAL_EV_RXCHAR) {
  172. Extension->HistoryMask |= SERIAL_EV_RXCHAR;
  173. }
  174. if ((Extension->IsrWaitMask & SERIAL_EV_RXFLAG) &&
  175. (Extension->SpecialChars.EventChar == rxchar)) {
  176. Extension->HistoryMask |= SERIAL_EV_RXFLAG;
  177. }
  178. if (Extension->IrpMaskLocation && Extension->HistoryMask) {
  179. *Extension->IrpMaskLocation = Extension->HistoryMask;
  180. Extension->IrpMaskLocation = NULL;
  181. Extension->HistoryMask = 0;
  182. Extension->CurrentWaitIrp->IoStatus.Information =
  183. sizeof(ULONG);
  184. CyyInsertQueueDpc(&Extension->CommWaitDpc,NULL,NULL,Extension);
  185. }
  186. }
  187. CyyPutChar(Extension,rxchar);
  188. // If we're doing line status and modem
  189. // status insertion then we need to insert
  190. // a zero following the character we just
  191. // placed into the buffer to mark that this
  192. // was reception of what we are using to
  193. // escape.
  194. if (Extension->EscapeChar &&
  195. (Extension->EscapeChar == rxchar)) {
  196. CyyPutChar(Extension,SERIAL_LSRMST_ESCAPE);
  197. }
  198. } // end for
  199. } else { // device is being closed, discard rx chars
  200. for(i = 0 ; i < x ; i++) rxchar = CD1400_READ(chip,bus,RDSR);
  201. } // end if device is opened else closed
  202. }
  203. } else {
  204. // No Extension
  205. if (x == 0x07) { // exception
  206. x = CD1400_READ(chip,bus,RDSR); // status
  207. } else { // good char
  208. x = CD1400_READ(chip,bus,RDCR); // number of chars
  209. for(i = 0 ; i < x ; i++) rxchar = CD1400_READ(chip,bus,RDSR);
  210. }
  211. }
  212. CD1400_WRITE(chip,bus,RIR,(save_xir & 0x3f)); // end service
  213. CD1400_WRITE(chip,bus,CAR,save_car);
  214. } // end reception
  215. if (status & 0x02) {
  216. //Transmission
  217. save_xir = CD1400_READ(chip,bus,TIR);
  218. channel = (ULONG) (save_xir & 0x03);
  219. save_car = CD1400_READ(chip,bus,CAR);
  220. CD1400_WRITE(chip,bus,CAR,save_xir);
  221. Extension = Dispatch->Extensions[channel + CYY_CHANNELS_PER_CHIP*chipindex];
  222. if (Extension) {
  223. //
  224. // Apply lock so if close happens concurrently we don't miss the DPC
  225. // queueing
  226. //
  227. if (interlockedExtension[channel] == NULL) {
  228. interlockedExtension[channel] = Extension;
  229. InterlockedIncrement(&Extension->DpcCount);
  230. LOGENTRY(LOG_CNT, 'DpI3', 0, Extension->DpcCount, 0); // Added in build 2128
  231. }
  232. Extension->HoldingEmpty = TRUE;
  233. if( Extension->DeviceIsOpened &&
  234. (Extension->PowerState == PowerDeviceD0)) {
  235. if (Extension->BreakCmd != NO_BREAK) {
  236. if (Extension->BreakCmd == SEND_BREAK) {
  237. if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
  238. SERIAL_TRANSMIT_TOGGLE) {
  239. CyySetRTS(Extension);
  240. }
  241. CD1400_WRITE(chip,bus,TDR,(unsigned char) 0x00); // escape sequence
  242. CD1400_WRITE(chip,bus,TDR,(unsigned char) 0x81); // Send Break
  243. Extension->TXHolding |= CYY_TX_BREAK;
  244. Extension->HoldingEmpty = FALSE;
  245. Extension->BreakCmd = DISABLE_ETC;
  246. } else if (Extension->BreakCmd == STOP_BREAK){
  247. if (Extension->TXHolding & CYY_TX_BREAK) {
  248. CD1400_WRITE(chip,bus,TDR,(unsigned char) 0x00); // escape sequence
  249. CD1400_WRITE(chip,bus,TDR,(unsigned char) 0x83); // Stop Break
  250. Extension->HoldingEmpty = FALSE;
  251. Extension->TXHolding &= ~CYY_TX_BREAK;
  252. }
  253. Extension->BreakCmd = DISABLE_ETC;
  254. } else if (Extension->BreakCmd == DISABLE_ETC) {
  255. UCHAR cor2;
  256. cor2 = CD1400_READ(chip,bus,COR2);
  257. CD1400_WRITE(chip,bus, COR2,cor2 & ~EMBED_TX_ENABLE); // disable ETC bit
  258. CyyCDCmd(Extension,CCR_CORCHG_COR2); // COR2 changed
  259. Extension->BreakCmd = NO_BREAK;
  260. if (!Extension->TXHolding &&
  261. (Extension->TransmitImmediate ||
  262. Extension->WriteLength) &&
  263. Extension->HoldingEmpty) {
  264. //CyyTxStart(Extension); no need for CyyTxStart from here.
  265. } else {
  266. UCHAR srer = CD1400_READ(chip,bus,SRER);
  267. CD1400_WRITE(chip,bus,SRER,srer & (~SRER_TXRDY));
  268. //
  269. // The following routine will lower the rts if we
  270. // are doing transmit toggleing and there is no
  271. // reason to keep it up.
  272. //
  273. Extension->CountOfTryingToLowerRTS++;
  274. CyyPerhapsLowerRTS(Extension);
  275. }
  276. }
  277. } else {
  278. // This is not a Send Break.
  279. // Check if there are bytes to be transmitted
  280. if (Extension->WriteLength || Extension->TransmitImmediate) {
  281. Extension->EmptiedTransmit = TRUE;
  282. if (Extension->HandFlow.ControlHandShake &
  283. SERIAL_OUT_HANDSHAKEMASK) {
  284. CyyHandleModemUpdate(Extension,TRUE);
  285. }
  286. if (Extension->TransmitImmediate&&(!Extension->TXHolding ||
  287. (Extension->TXHolding == CYY_TX_XOFF) )) {
  288. Extension->TransmitImmediate = FALSE;
  289. if ((Extension->HandFlow.FlowReplace &
  290. SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) {
  291. CyySetRTS(Extension);
  292. Extension->PerfStats.TransmittedCount++;
  293. Extension->WmiPerfData.TransmittedCount++;
  294. CD1400_WRITE(chip,bus,TDR,(unsigned char)(Extension->ImmediateChar));
  295. CyyInsertQueueDpc(
  296. &Extension->StartTimerLowerRTSDpc,NULL,NULL,
  297. Extension)? Extension->CountOfTryingToLowerRTS++:0;
  298. } else {
  299. Extension->PerfStats.TransmittedCount++;
  300. Extension->WmiPerfData.TransmittedCount++;
  301. CD1400_WRITE(chip,bus,TDR,(unsigned char)(Extension->ImmediateChar));
  302. }
  303. Extension->HoldingEmpty = FALSE;
  304. CyyInsertQueueDpc(
  305. &Extension->CompleteImmediateDpc,
  306. NULL,
  307. NULL,
  308. Extension
  309. );
  310. } else if (!Extension->TXHolding) {
  311. ULONG amountToWrite;
  312. amountToWrite =
  313. (Extension->TxFifoAmount < Extension->WriteLength)?
  314. Extension->TxFifoAmount:Extension->WriteLength;
  315. if ((Extension->HandFlow.FlowReplace &
  316. SERIAL_RTS_MASK) ==
  317. SERIAL_TRANSMIT_TOGGLE) {
  318. // We have to raise if we're sending
  319. // this character.
  320. CyySetRTS(Extension);
  321. for(i = 0 ; i < amountToWrite ; i++) { // write to FIFO
  322. CD1400_WRITE(chip,bus,TDR,((unsigned char *)
  323. (Extension->WriteCurrentChar))[i]);
  324. }
  325. Extension->PerfStats.TransmittedCount += amountToWrite;
  326. Extension->WmiPerfData.TransmittedCount += amountToWrite;
  327. CyyInsertQueueDpc(
  328. &Extension->StartTimerLowerRTSDpc,
  329. NULL,
  330. NULL,
  331. Extension
  332. )?Extension->CountOfTryingToLowerRTS++:0;
  333. } else {
  334. for(i = 0 ; i < amountToWrite ; i++) { // write to FIFO
  335. CD1400_WRITE(chip,bus,TDR,((unsigned char *)
  336. (Extension->WriteCurrentChar))[i]);
  337. }
  338. Extension->PerfStats.TransmittedCount += amountToWrite;
  339. Extension->WmiPerfData.TransmittedCount += amountToWrite;
  340. }
  341. Extension->HoldingEmpty = FALSE;
  342. Extension->WriteCurrentChar += amountToWrite;
  343. Extension->WriteLength -= amountToWrite;
  344. if (!Extension->WriteLength) {
  345. PIO_STACK_LOCATION IrpSp;
  346. //
  347. // No More characters left. This
  348. // write is complete. Take care
  349. // when updating the information field,
  350. // we could have an xoff counter masquerading
  351. // as a write irp.
  352. //
  353. IrpSp = IoGetCurrentIrpStackLocation(
  354. Extension->CurrentWriteIrp
  355. );
  356. Extension->CurrentWriteIrp->IoStatus.Information =
  357. (IrpSp->MajorFunction == IRP_MJ_WRITE)?
  358. (IrpSp->Parameters.Write.Length):
  359. (1);
  360. CyyInsertQueueDpc(
  361. &Extension->CompleteWriteDpc,
  362. NULL,
  363. NULL,
  364. Extension
  365. );
  366. } // end write complete
  367. } // end of if(!TXHolding)
  368. } else { // nothing to be transmitted - disable interrupts.
  369. UCHAR srer;
  370. Extension->EmptiedTransmit = TRUE;
  371. srer = CD1400_READ(chip,bus,SRER);
  372. CD1400_WRITE(chip,bus,SRER,srer & (~SRER_TXRDY));
  373. }
  374. } // end of if(break)
  375. } else { // Device is closed. Disable interrupts
  376. UCHAR srer = CD1400_READ(chip,bus,SRER);
  377. CD1400_WRITE(chip,bus,SRER,srer & (~SRER_TXRDY));
  378. Extension->EmptiedTransmit = TRUE;
  379. }
  380. } else {
  381. // Device was not created, no extension attached.
  382. UCHAR srer = CD1400_READ(chip,bus,SRER);
  383. CD1400_WRITE(chip,bus,SRER,srer & (~SRER_TXRDY));
  384. } // end if Extension
  385. CD1400_WRITE(chip,bus,TIR,(save_xir & 0x3f)); // end service
  386. CD1400_WRITE(chip,bus,CAR,save_car);
  387. } // end transmission
  388. if (status & 0x04) {
  389. //Modem
  390. save_xir = CD1400_READ(chip,bus,MIR);
  391. channel = (ULONG) (save_xir & 0x03);
  392. save_car = CD1400_READ(chip,bus,CAR);
  393. CD1400_WRITE(chip,bus,CAR,save_xir);
  394. //CyyDump(CYYDIAG5,("modem\n"));
  395. Extension = Dispatch->Extensions[channel + CYY_CHANNELS_PER_CHIP*chipindex];
  396. if (Extension) {
  397. //
  398. // Apply lock so if close happens concurrently we don't miss the DPC
  399. // queueing
  400. //
  401. if (interlockedExtension[channel] == NULL) {
  402. interlockedExtension[channel] = Extension;
  403. InterlockedIncrement(&Extension->DpcCount);
  404. LOGENTRY(LOG_CNT, 'DpI3', 0, Extension->DpcCount, 0); // Added in build 2128
  405. }
  406. if (Extension->DeviceIsOpened &&
  407. (Extension->PowerState == PowerDeviceD0)) {
  408. misr = CD1400_READ(chip,bus,MISR);
  409. CyyHandleModemUpdateForModem(Extension,FALSE,misr);
  410. }
  411. }
  412. CD1400_WRITE(chip,bus,MIR,(save_xir & 0x3f)); // end service
  413. CD1400_WRITE(chip,bus,CAR,save_car);
  414. } // end modem
  415. } // end READ SVRR
  416. if (thisChipInterrupted) {
  417. for (channel=0; channel<CYY_CHANNELS_PER_CHIP; channel++) {
  418. if (Extension = interlockedExtension[channel]) {
  419. LONG pendingCnt;
  420. //
  421. // Increment once more. This is just a quick test to see if we
  422. // have a chance of causing the event to fire... we don't want
  423. // to run a DPC on every ISR if we don't have to....
  424. //
  425. retryDPCFiring:;
  426. InterlockedIncrement(&Extension->DpcCount);
  427. LOGENTRY(LOG_CNT, 'DpI4', 0, Extension->DpcCount, 0); // Added in build 2128
  428. //
  429. // Decrement and see if the lock above looks like the only one left.
  430. //
  431. pendingCnt = InterlockedDecrement(&Extension->DpcCount);
  432. // LOGENTRY(LOG_CNT, 'DpD5', 0, Extension->DpcCount, 0); // Added in build 2128
  433. if (pendingCnt == 1) {
  434. KeInsertQueueDpc(&Extension->IsrUnlockPagesDpc, NULL, NULL);
  435. } else {
  436. if (InterlockedDecrement(&Extension->DpcCount) == 0) {
  437. // LOGENTRY(LOG_CNT, 'DpD6', &Extension->IsrUnlockPagesDpc, // Added in bld 2128
  438. // Extension->DpcCount, 0);
  439. //
  440. // We missed it. Retry...
  441. //
  442. InterlockedIncrement(&Extension->DpcCount);
  443. goto retryDPCFiring;
  444. }
  445. }
  446. } // if (Extension = interlockedExtension[])
  447. } // for (;channel<CYY_CHANNELS_PER_CHIP;)
  448. portindex = (chipindex+1)*4;
  449. continue;
  450. } // if (thisChipInterrupted)
  451. portindex++;
  452. } // for(;portindex<CYY_MAX_PORTS;);
  453. if (mappedboard) {
  454. CYY_CLEAR_INTERRUPT(mappedboard,Dispatch->IsPci);
  455. }
  456. //DbgPrint("<Isr\n");
  457. return ServicedAnInterrupt;
  458. }
  459. VOID
  460. CyyPutChar(
  461. IN PCYY_DEVICE_EXTENSION Extension,
  462. IN UCHAR CharToPut
  463. )
  464. /*--------------------------------------------------------------------------
  465. CyyPutChar()
  466. Routine Description: This routine, which only runs at device level,
  467. takes care of placing a character into the typeahead (receive) buffer.
  468. Arguments:
  469. Extension - The serial device extension.
  470. Return Value: None.
  471. --------------------------------------------------------------------------*/
  472. {
  473. CYY_LOCKED_PAGED_CODE();
  474. // If we have dsr sensitivity enabled then
  475. // we need to check the modem status register
  476. // to see if it has changed.
  477. if (Extension->HandFlow.ControlHandShake & SERIAL_DSR_SENSITIVITY) {
  478. CyyHandleModemUpdate(Extension,FALSE);
  479. if (Extension->RXHolding & CYY_RX_DSR) {
  480. // We simply act as if we haven't seen the character if
  481. // dsr line is low.
  482. return;
  483. }
  484. }
  485. // If the xoff counter is non-zero then decrement it.
  486. // If the counter then goes to zero, complete that irp.
  487. if (Extension->CountSinceXoff) {
  488. Extension->CountSinceXoff--;
  489. if (!Extension->CountSinceXoff) {
  490. Extension->CurrentXoffIrp->IoStatus.Status = STATUS_SUCCESS;
  491. Extension->CurrentXoffIrp->IoStatus.Information = 0;
  492. CyyInsertQueueDpc(&Extension->XoffCountCompleteDpc,NULL,NULL,Extension);
  493. }
  494. }
  495. // Check to see if we are copying into the
  496. // users buffer or into the interrupt buffer.
  497. //
  498. // If we are copying into the user buffer
  499. // then we know there is always room for one more.
  500. // (We know this because if there wasn't room
  501. // then that read would have completed and we
  502. // would be using the interrupt buffer.)
  503. //
  504. // If we are copying into the interrupt buffer
  505. // then we will need to check if we have enough
  506. // room.
  507. if (Extension->ReadBufferBase != Extension->InterruptReadBuffer) {
  508. // Increment the following value so
  509. // that the interval timer (if one exists
  510. // for this read) can know that a character
  511. // has been read.
  512. Extension->ReadByIsr++;
  513. // We are in the user buffer. Place the character into the buffer.
  514. // See if the read is complete.
  515. *Extension->CurrentCharSlot = CharToPut;
  516. if (Extension->CurrentCharSlot == Extension->LastCharSlot) {
  517. // We've filled up the users buffer.
  518. // Switch back to the interrupt buffer
  519. // and send off a DPC to Complete the read.
  520. //
  521. // It is inherent that when we were using
  522. // a user buffer that the interrupt buffer
  523. // was empty.
  524. Extension->ReadBufferBase = Extension->InterruptReadBuffer;
  525. Extension->CurrentCharSlot = Extension->InterruptReadBuffer;
  526. Extension->FirstReadableChar = Extension->InterruptReadBuffer;
  527. Extension->LastCharSlot = Extension->InterruptReadBuffer +
  528. (Extension->BufferSize - 1);
  529. Extension->CharsInInterruptBuffer = 0;
  530. Extension->CurrentReadIrp->IoStatus.Information =
  531. IoGetCurrentIrpStackLocation(
  532. Extension->CurrentReadIrp
  533. )->Parameters.Read.Length;
  534. CyyInsertQueueDpc(&Extension->CompleteReadDpc,NULL,NULL,Extension);
  535. } else {
  536. // Not done with the users read.
  537. Extension->CurrentCharSlot++;
  538. }
  539. } else {
  540. // We need to see if we reached our flow
  541. // control threshold. If we have then
  542. // we turn on whatever flow control the
  543. // owner has specified. If no flow
  544. // control was specified, well..., we keep
  545. // trying to receive characters and hope that
  546. // we have enough room. Note that no matter
  547. // what flow control protocol we are using, it
  548. // will not prevent us from reading whatever
  549. // characters are available.
  550. if ((Extension->HandFlow.ControlHandShake
  551. & SERIAL_DTR_MASK) ==
  552. SERIAL_DTR_HANDSHAKE) {
  553. // If we are already doing a
  554. // dtr hold then we don't have
  555. // to do anything else.
  556. if (!(Extension->RXHolding &
  557. CYY_RX_DTR)) {
  558. if ((Extension->BufferSize -
  559. Extension->HandFlow.XoffLimit)
  560. <= (Extension->CharsInInterruptBuffer+1)) {
  561. Extension->RXHolding |= CYY_RX_DTR;
  562. CyyClrDTR(Extension);
  563. }
  564. }
  565. }
  566. if ((Extension->HandFlow.FlowReplace
  567. & SERIAL_RTS_MASK) ==
  568. SERIAL_RTS_HANDSHAKE) {
  569. // If we are already doing a
  570. // rts hold then we don't have
  571. // to do anything else.
  572. if (!(Extension->RXHolding & CYY_RX_RTS)) {
  573. if ((Extension->BufferSize -
  574. Extension->HandFlow.XoffLimit)
  575. <= (Extension->CharsInInterruptBuffer+1)) {
  576. Extension->RXHolding |= CYY_RX_RTS;
  577. CyyClrRTS(Extension);
  578. }
  579. }
  580. }
  581. if (Extension->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) {
  582. // If we are already doing a
  583. // xoff hold then we don't have
  584. // to do anything else.
  585. if (!(Extension->RXHolding & CYY_RX_XOFF)) {
  586. if ((Extension->BufferSize -
  587. Extension->HandFlow.XoffLimit)
  588. <= (Extension->CharsInInterruptBuffer+1)) {
  589. Extension->RXHolding |= CYY_RX_XOFF;
  590. // If necessary cause an
  591. // off to be sent.
  592. CyyProdXonXoff(Extension,FALSE);
  593. }
  594. }
  595. }
  596. if (Extension->CharsInInterruptBuffer < Extension->BufferSize) {
  597. *Extension->CurrentCharSlot = CharToPut;
  598. Extension->CharsInInterruptBuffer++;
  599. // If we've become 80% full on this character
  600. // and this is an interesting event, note it.
  601. if (Extension->CharsInInterruptBuffer == Extension->BufferSizePt8) {
  602. if (Extension->IsrWaitMask & SERIAL_EV_RX80FULL) {
  603. Extension->HistoryMask |= SERIAL_EV_RX80FULL;
  604. if (Extension->IrpMaskLocation) {
  605. *Extension->IrpMaskLocation = Extension->HistoryMask;
  606. Extension->IrpMaskLocation = NULL;
  607. Extension->HistoryMask = 0;
  608. Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
  609. CyyInsertQueueDpc(&Extension->CommWaitDpc,NULL,NULL,Extension);
  610. }
  611. }
  612. }
  613. // Point to the next available space
  614. // for a received character. Make sure
  615. // that we wrap around to the beginning
  616. // of the buffer if this last character
  617. // received was placed at the last slot
  618. // in the buffer.
  619. if (Extension->CurrentCharSlot == Extension->LastCharSlot) {
  620. Extension->CurrentCharSlot = Extension->InterruptReadBuffer;
  621. } else {
  622. Extension->CurrentCharSlot++;
  623. }
  624. } else {
  625. // We have a new character but no room for it.
  626. Extension->PerfStats.BufferOverrunErrorCount++;
  627. Extension->WmiPerfData.BufferOverrunErrorCount++;
  628. Extension->ErrorWord |= SERIAL_ERROR_QUEUEOVERRUN;
  629. if (Extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR) {
  630. // Place the error character into the last
  631. // valid place for a character. Be careful!,
  632. // that place might not be the previous location!
  633. if (Extension->CurrentCharSlot == Extension->InterruptReadBuffer) {
  634. *(Extension->InterruptReadBuffer+
  635. (Extension->BufferSize-1)) =
  636. Extension->SpecialChars.ErrorChar;
  637. } else {
  638. *(Extension->CurrentCharSlot-1) =
  639. Extension->SpecialChars.ErrorChar;
  640. }
  641. }
  642. // If the application has requested it, abort all reads
  643. // and writes on an error.
  644. if (Extension->HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) {
  645. CyyInsertQueueDpc(&Extension->CommErrorDpc,NULL,NULL,Extension);
  646. }
  647. }
  648. }
  649. }
  650. BOOLEAN
  651. CyyProcessLSR(
  652. IN PCYY_DEVICE_EXTENSION Extension,
  653. IN UCHAR Rdsr,
  654. IN UCHAR RxChar
  655. )
  656. /*++
  657. Routine Description:
  658. This routine, which only runs at device level, reads the
  659. ISR and totally processes everything that might have
  660. changed.
  661. Arguments:
  662. Extension - The serial device extension.
  663. Return Value:
  664. TRUE if RxChar still needs to be processed.
  665. --*/
  666. {
  667. BOOLEAN StillProcessRxChar=TRUE;
  668. UCHAR LineStatus=0;
  669. CYY_LOCKED_PAGED_CODE();
  670. if (Rdsr & CYY_LSR_OE)
  671. LineStatus |= SERIAL_LSR_OE;
  672. if (Rdsr & CYY_LSR_FE)
  673. LineStatus |= SERIAL_LSR_FE;
  674. if (Rdsr & CYY_LSR_PE)
  675. LineStatus |= SERIAL_LSR_PE;
  676. if (Rdsr & CYY_LSR_BI)
  677. LineStatus |= SERIAL_LSR_BI;
  678. if (Extension->EscapeChar) {
  679. CyyPutChar(
  680. Extension,
  681. Extension->EscapeChar
  682. );
  683. CyyPutChar(
  684. Extension,
  685. (UCHAR)((LineStatus & SERIAL_LSR_OE)?
  686. (SERIAL_LSRMST_LSR_NODATA):(SERIAL_LSRMST_LSR_DATA))
  687. );
  688. CyyPutChar(
  689. Extension,
  690. LineStatus
  691. );
  692. if (!(LineStatus & SERIAL_LSR_OE)) {
  693. Extension->PerfStats.ReceivedCount++;
  694. Extension->WmiPerfData.ReceivedCount++;
  695. CyyPutChar(
  696. Extension,
  697. RxChar
  698. );
  699. StillProcessRxChar = FALSE;
  700. }
  701. }
  702. if (LineStatus & SERIAL_LSR_OE) {
  703. Extension->PerfStats.SerialOverrunErrorCount++;
  704. Extension->WmiPerfData.SerialOverrunErrorCount++;
  705. Extension->ErrorWord |= SERIAL_ERROR_OVERRUN;
  706. if (Extension->HandFlow.FlowReplace &
  707. SERIAL_ERROR_CHAR) {
  708. CyyPutChar(
  709. Extension,
  710. Extension->SpecialChars.ErrorChar
  711. );
  712. }
  713. StillProcessRxChar = FALSE;
  714. }
  715. if (LineStatus & SERIAL_LSR_BI) {
  716. Extension->ErrorWord |= SERIAL_ERROR_BREAK;
  717. if (Extension->HandFlow.FlowReplace &
  718. SERIAL_BREAK_CHAR) {
  719. CyyPutChar(
  720. Extension,
  721. Extension->SpecialChars.BreakChar
  722. );
  723. }
  724. } else {
  725. //
  726. // Framing errors only count if they
  727. // occur exclusive of a break being
  728. // received.
  729. //
  730. if (LineStatus & SERIAL_LSR_PE) {
  731. Extension->PerfStats.ParityErrorCount++;
  732. Extension->WmiPerfData.ParityErrorCount++;
  733. Extension->ErrorWord |= SERIAL_ERROR_PARITY;
  734. if (Extension->HandFlow.FlowReplace &
  735. SERIAL_ERROR_CHAR) {
  736. CyyPutChar(
  737. Extension,
  738. Extension->SpecialChars.ErrorChar
  739. );
  740. StillProcessRxChar = FALSE;
  741. }
  742. }
  743. if (LineStatus & SERIAL_LSR_FE) {
  744. Extension->PerfStats.FrameErrorCount++;
  745. Extension->WmiPerfData.FrameErrorCount++;
  746. Extension->ErrorWord |= SERIAL_ERROR_FRAMING;
  747. if (Extension->HandFlow.FlowReplace &
  748. SERIAL_ERROR_CHAR) {
  749. CyyPutChar(
  750. Extension,
  751. Extension->SpecialChars.ErrorChar
  752. );
  753. StillProcessRxChar = FALSE;
  754. }
  755. }
  756. }
  757. //
  758. // If the application has requested it,
  759. // abort all the reads and writes
  760. // on an error.
  761. //
  762. if (Extension->HandFlow.ControlHandShake &
  763. SERIAL_ERROR_ABORT) {
  764. CyyInsertQueueDpc(
  765. &Extension->CommErrorDpc,
  766. NULL,
  767. NULL,
  768. Extension
  769. );
  770. }
  771. //
  772. // Check to see if we have a wait
  773. // pending on the comm error events. If we
  774. // do then we schedule a dpc to satisfy
  775. // that wait.
  776. //
  777. if (Extension->IsrWaitMask) {
  778. if ((Extension->IsrWaitMask & SERIAL_EV_ERR) &&
  779. (LineStatus & (SERIAL_LSR_OE |
  780. SERIAL_LSR_PE |
  781. SERIAL_LSR_FE))) {
  782. Extension->HistoryMask |= SERIAL_EV_ERR;
  783. }
  784. if ((Extension->IsrWaitMask & SERIAL_EV_BREAK) &&
  785. (LineStatus & SERIAL_LSR_BI)) {
  786. Extension->HistoryMask |= SERIAL_EV_BREAK;
  787. }
  788. if (Extension->IrpMaskLocation &&
  789. Extension->HistoryMask) {
  790. *Extension->IrpMaskLocation =
  791. Extension->HistoryMask;
  792. Extension->IrpMaskLocation = NULL;
  793. Extension->HistoryMask = 0;
  794. Extension->CurrentWaitIrp->IoStatus.Information =
  795. sizeof(ULONG);
  796. CyyInsertQueueDpc(
  797. &Extension->CommWaitDpc,
  798. NULL,
  799. NULL,
  800. Extension
  801. );
  802. }
  803. }
  804. return StillProcessRxChar;
  805. }
  806. BOOLEAN
  807. CyyTxStart(
  808. IN PVOID Context
  809. )
  810. /*--------------------------------------------------------------------------
  811. CyyTxStart()
  812. Description: Enable Tx interrupt.
  813. Parameters:
  814. Exetnsion: Pointer to device extension.
  815. Return Value: None
  816. --------------------------------------------------------------------------*/
  817. {
  818. PCYY_DEVICE_EXTENSION Extension = Context;
  819. PUCHAR chip = Extension->Cd1400;
  820. ULONG bus = Extension->IsPci;
  821. UCHAR srer;
  822. if (Extension->PowerState == PowerDeviceD0) {
  823. CD1400_WRITE(chip,bus,CAR,Extension->CdChannel & 0x03);
  824. srer = CD1400_READ (chip,bus,SRER);
  825. CD1400_WRITE(chip,bus,SRER,srer | SRER_TXRDY);
  826. }
  827. return(FALSE);
  828. }
  829. BOOLEAN
  830. CyySendXon(
  831. IN PVOID Context
  832. )
  833. /*--------------------------------------------------------------------------
  834. CyySendXon()
  835. Description: Send a Xon.
  836. Parameters:
  837. Exetension: Pointer to device extension.
  838. Return Value: Always FALSE.
  839. --------------------------------------------------------------------------*/
  840. {
  841. PCYY_DEVICE_EXTENSION Extension = Context;
  842. PUCHAR chip = Extension->Cd1400;
  843. ULONG bus = Extension->IsPci;
  844. if(!(Extension->TXHolding & ~CYY_TX_XOFF)) {
  845. if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
  846. SERIAL_TRANSMIT_TOGGLE) {
  847. CyySetRTS(Extension);
  848. Extension->PerfStats.TransmittedCount++;
  849. Extension->WmiPerfData.TransmittedCount++;
  850. CD1400_WRITE(chip,bus,CAR,Extension->CdChannel & 0x03);
  851. CyyCDCmd(Extension,CCR_SENDSC_SCHR1);
  852. CyyInsertQueueDpc(&Extension->StartTimerLowerRTSDpc,NULL,
  853. NULL,Extension)?Extension->CountOfTryingToLowerRTS++:0;
  854. } else {
  855. Extension->PerfStats.TransmittedCount++;
  856. Extension->WmiPerfData.TransmittedCount++;
  857. CD1400_WRITE(chip,bus,CAR,Extension->CdChannel & 0x03);
  858. CyyCDCmd(Extension,CCR_SENDSC_SCHR1);
  859. }
  860. // If we send an xon, by definition we can't be holding by Xoff.
  861. Extension->TXHolding &= ~CYY_TX_XOFF;
  862. Extension->RXHolding &= ~CYY_RX_XOFF;
  863. }
  864. return(FALSE);
  865. }
  866. BOOLEAN
  867. CyySendXoff(
  868. IN PVOID Context
  869. )
  870. /*--------------------------------------------------------------------------
  871. CyySendXoff()
  872. Description: Send a Xoff.
  873. Parameters:
  874. Extension: Pointer to device extension.
  875. Return Value: Always FALSE.
  876. --------------------------------------------------------------------------*/
  877. {
  878. PCYY_DEVICE_EXTENSION Extension = Context;
  879. PUCHAR chip = Extension->Cd1400;
  880. ULONG bus = Extension->IsPci;
  881. if(!Extension->TXHolding) {
  882. if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
  883. SERIAL_TRANSMIT_TOGGLE) {
  884. CyySetRTS(Extension);
  885. Extension->PerfStats.TransmittedCount++;
  886. Extension->WmiPerfData.TransmittedCount++;
  887. CD1400_WRITE(chip,bus,CAR,Extension->CdChannel & 0x03);
  888. CyyCDCmd(Extension,CCR_SENDSC_SCHR2);
  889. CyyInsertQueueDpc(&Extension->StartTimerLowerRTSDpc,NULL,
  890. NULL,Extension)?Extension->CountOfTryingToLowerRTS++:0;
  891. } else {
  892. Extension->PerfStats.TransmittedCount++;
  893. Extension->WmiPerfData.TransmittedCount++;
  894. CD1400_WRITE(chip,bus,CAR,Extension->CdChannel & 0x03);
  895. CyyCDCmd(Extension,CCR_SENDSC_SCHR2);
  896. }
  897. // no xoff is sent if the transmission is already held up.
  898. // If xoff continue mode is set, we don't actually stop sending
  899. if (!(Extension->HandFlow.FlowReplace & SERIAL_XOFF_CONTINUE)) {
  900. Extension->TXHolding |= CYY_TX_XOFF;
  901. if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
  902. SERIAL_TRANSMIT_TOGGLE) {
  903. CyyInsertQueueDpc(&Extension->StartTimerLowerRTSDpc,NULL,
  904. NULL,Extension)?Extension->CountOfTryingToLowerRTS++:0;
  905. }
  906. }
  907. }
  908. return(FALSE);
  909. }
  910.