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.

483 lines
15 KiB

  1. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Copyright (c) 1991, 1992, 1993 Microsoft Corporation
  3. Module Name:
  4. isr.c
  5. Abstract:
  6. This module contains the interrupt service routine for the
  7. serial driver.
  8. Author:
  9. Anthony V. Ercolano 26-Sep-1991
  10. Environment:
  11. Kernel mode
  12. Revision History :
  13. -----------------------------------------------------------------------------*/
  14. #include "precomp.h"
  15. BOOLEAN
  16. SerialISR(IN PKINTERRUPT InterruptObject, IN PVOID Context)
  17. {
  18. // Holds the information specific to handling this device.
  19. PCARD_DEVICE_EXTENSION pCard = Context;
  20. PPORT_DEVICE_EXTENSION pPort;
  21. BOOLEAN ServicedAnInterrupt = FALSE;
  22. PUART_OBJECT pUart = pCard->pFirstUart;
  23. DWORD IntsPending = 0;
  24. UNREFERENCED_PARAMETER(InterruptObject);
  25. #ifndef BUILD_SPXMINIPORT
  26. // If the card is not powered, delay interrupt service until it is.
  27. if(!(pCard->PnpPowerFlags & PPF_POWERED) && (pCard->PnpPowerFlags & PPF_STARTED))
  28. return ServicedAnInterrupt; // Most likely the interrupt is not ours anyway.
  29. #endif
  30. switch(pCard->CardType)
  31. {
  32. case Fast4_Isa:
  33. case Fast4_Pci:
  34. case RAS4_Pci:
  35. {
  36. if((READ_PORT_UCHAR(pCard->Controller + FAST_UARTS_0_TO_7_INTS_REG) & FAST_UARTS_0_TO_3_INT_PENDING) == 0)
  37. return ServicedAnInterrupt; // If no Uarts have interrupts pending then return.
  38. break;
  39. }
  40. case Fast8_Isa:
  41. case Fast8_Pci:
  42. case RAS8_Pci:
  43. {
  44. if(READ_PORT_UCHAR(pCard->Controller + FAST_UARTS_0_TO_7_INTS_REG) == 0)
  45. return ServicedAnInterrupt; // If no Uarts have interrupts pending then return.
  46. break;
  47. }
  48. case Fast16_Isa:
  49. case Fast16_Pci:
  50. case Fast16FMC_Pci:
  51. {
  52. if((READ_PORT_UCHAR(pCard->Controller + FAST_UARTS_0_TO_7_INTS_REG) == 0)
  53. && (READ_PORT_UCHAR(pCard->Controller + FAST_UARTS_9_TO_16_INTS_REG) == 0))
  54. return ServicedAnInterrupt; // If no Uarts have interrupts pending then return.
  55. break;
  56. }
  57. break;
  58. case Speed2_Pci:
  59. case Speed2P_Pci:
  60. case Speed4_Pci:
  61. case Speed4P_Pci:
  62. {
  63. if((READ_REGISTER_ULONG( (PULONG)(pCard->LocalConfigRegisters + SPEED_GIS_REG)) & INTERNAL_UART_INT_PENDING) == 0)
  64. return ServicedAnInterrupt; // If no Uarts have interrupts pending then return.
  65. break;
  66. }
  67. case Speed2and4_Pci_8BitBus:
  68. case Speed2P_Pci_8BitBus:
  69. case Speed4P_Pci_8BitBus:
  70. return ServicedAnInterrupt; // No UARTs therefore NO interrupts that are ours - we hope.
  71. break;
  72. default:
  73. break;
  74. }
  75. if(pUart)
  76. {
  77. while((IntsPending = pCard->UartLib.UL_IntsPending_XXXX(&pUart)))
  78. {
  79. pPort = (PPORT_DEVICE_EXTENSION) pCard->UartLib.UL_GetAppBackPtr_XXXX(pUart); // Get Port Extension for UART.
  80. SpxDbgMsg(ISRINFO, ("%s: Int on 0x%lX", PRODUCT_NAME, IntsPending));
  81. // Service receive status interrupts
  82. if(IntsPending & UL_IP_RX_STAT)
  83. {
  84. BYTE LineStatus = 0;
  85. DWORD RxStatus;
  86. pPort->pUartLib->UL_GetStatus_XXXX(pUart, &RxStatus, UL_GS_OP_LINESTATUS);
  87. // If OVERRUN/PARITY/FRAMING/DATA/BREAK error
  88. if(RxStatus & (UL_US_OVERRUN_ERROR | UL_US_PARITY_ERROR | UL_US_FRAMING_ERROR | UL_US_DATA_ERROR | UL_US_BREAK_ERROR))
  89. {
  90. BYTE TmpByte;
  91. // If the application has requested it, abort all the reads and writes on an error.
  92. if(pPort->HandFlow.ControlHandShake & SERIAL_ERROR_ABORT)
  93. KeInsertQueueDpc(&pPort->CommErrorDpc, NULL, NULL);
  94. /*
  95. if(pPort->EscapeChar)
  96. {
  97. TmpByte = pPort->EscapeChar;
  98. pPort->pUartLib->UL_ImmediateByte_XXXX(pPort->pUart, &TmpByte, UL_IM_OP_WRITE);
  99. if(RxStatus & UL_US_DATA_ERROR)
  100. {
  101. TmpByte = SERIAL_LSRMST_LSR_DATA
  102. pPort->pUartLib->UL_ImmediateByte_XXXX(pPort->pUart, &TmpByte, UL_IM_OP_WRITE);
  103. }
  104. else
  105. {
  106. TmpByte = SERIAL_LSRMST_LSR_NODATA
  107. pPort->pUartLib->UL_ImmediateByte_XXXX(pPort->pUart, &TmpByte, UL_IM_OP_WRITE);
  108. }
  109. }
  110. */
  111. if(RxStatus & UL_US_OVERRUN_ERROR)
  112. {
  113. pPort->ErrorWord |= SERIAL_ERROR_OVERRUN;
  114. LineStatus |= SERIAL_LSR_OE;
  115. pPort->PerfStats.SerialOverrunErrorCount++;
  116. #ifdef WMI_SUPPORT
  117. pPort->WmiPerfData.SerialOverrunErrorCount++;
  118. #endif
  119. }
  120. if(RxStatus & UL_US_PARITY_ERROR)
  121. {
  122. pPort->ErrorWord |= SERIAL_ERROR_PARITY;
  123. LineStatus |= SERIAL_LSR_PE;
  124. pPort->PerfStats.ParityErrorCount++;
  125. #ifdef WMI_SUPPORT
  126. pPort->WmiPerfData.ParityErrorCount++;
  127. #endif
  128. }
  129. if(RxStatus & UL_US_FRAMING_ERROR)
  130. {
  131. pPort->ErrorWord |= SERIAL_ERROR_FRAMING;
  132. LineStatus |= SERIAL_LSR_FE;
  133. pPort->PerfStats.FrameErrorCount++;
  134. #ifdef WMI_SUPPORT
  135. pPort->WmiPerfData.FrameErrorCount++;
  136. #endif
  137. }
  138. if(RxStatus & UL_US_DATA_ERROR)
  139. {
  140. LineStatus |= SERIAL_LSR_DR;
  141. }
  142. if(RxStatus & UL_US_BREAK_ERROR)
  143. {
  144. pPort->ErrorWord |= SERIAL_ERROR_BREAK;
  145. LineStatus |= SERIAL_LSR_BI;
  146. }
  147. /*
  148. if(pPort->EscapeChar)
  149. {
  150. TmpByte = LineStatus;
  151. pPort->pUartLib->UL_ImmediateByte_XXXX(pPort->pUart, &TmpByte, UL_IM_OP_WRITE);
  152. }
  153. if(RxStatus & (UL_US_OVERRUN_ERROR | UL_US_PARITY_ERROR | UL_US_FRAMING_ERROR | UL_US_DATA_ERROR))
  154. {
  155. if(pPort->HandFlow.FlowReplace & SERIAL_ERROR_CHAR)
  156. {
  157. TmpByte = pPort->SpecialChars.ErrorChar;
  158. pPort->pUartLib->UL_ImmediateByte_XXXX(pPort->pUart, &TmpByte, UL_IM_OP_WRITE);
  159. }
  160. }
  161. */
  162. }
  163. if(pPort->IsrWaitMask)
  164. {
  165. if((pPort->IsrWaitMask & SERIAL_EV_ERR)
  166. && (RxStatus & (UL_US_OVERRUN_ERROR | UL_US_PARITY_ERROR | UL_US_FRAMING_ERROR | UL_US_DATA_ERROR)))
  167. {
  168. // if we detected a overrun/parity/framing/data error
  169. pPort->HistoryMask |= SERIAL_EV_ERR;
  170. }
  171. // if we detected a break error
  172. if((pPort->IsrWaitMask & SERIAL_EV_BREAK) && (RxStatus & UL_US_BREAK_ERROR))
  173. pPort->HistoryMask |= SERIAL_EV_BREAK;
  174. #ifdef USE_HW_TO_DETECT_CHAR
  175. // if we detected the special char
  176. if((pPort->IsrWaitMask & SERIAL_EV_RXFLAG) && (RxStatus & UL_RS_SPECIAL_CHAR_DETECTED))
  177. pPort->HistoryMask |= SERIAL_EV_RXFLAG;
  178. #endif
  179. if(pPort->IrpMaskLocation && pPort->HistoryMask)
  180. {
  181. *pPort->IrpMaskLocation = pPort->HistoryMask;
  182. pPort->IrpMaskLocation = NULL;
  183. pPort->HistoryMask = 0;
  184. pPort->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
  185. // Mark IRP as about to complete normally to prevent cancel & timer DPCs
  186. // from doing so before DPC is allowed to run.
  187. //SERIAL_SET_REFERENCE(pPort->CurrentWaitIrp, SERIAL_REF_COMPLETING);
  188. KeInsertQueueDpc(&pPort->CommWaitDpc, NULL, NULL);
  189. }
  190. }
  191. }
  192. // Service receive and receive timeout interrupts.
  193. if((IntsPending & UL_IP_RX) || (IntsPending & UL_IP_RXTO))
  194. {
  195. DWORD StatusFlags = 0;
  196. int BytesReceived = pPort->pUartLib->UL_InputData_XXXX(pUart, &StatusFlags);
  197. if(StatusFlags & UL_RS_BUFFER_OVERRUN)
  198. {
  199. // We have a new character but no room for it.
  200. pPort->ErrorWord |= SERIAL_ERROR_QUEUEOVERRUN;
  201. pPort->PerfStats.BufferOverrunErrorCount++;
  202. #ifdef WMI_SUPPORT
  203. pPort->WmiPerfData.BufferOverrunErrorCount++;
  204. #endif
  205. }
  206. if(BytesReceived)
  207. {
  208. ULONG AmountInBuffer = 0;
  209. GET_BUFFER_STATE BufferState;
  210. pPort->ReadByIsr += BytesReceived;
  211. pPort->PerfStats.ReceivedCount += BytesReceived; // Increment Rx Counter
  212. #ifdef WMI_SUPPORT
  213. pPort->WmiPerfData.ReceivedCount += BytesReceived;
  214. #endif
  215. pPort->pUartLib->UL_BufferControl_XXXX(pUart, &BufferState, UL_BC_OP_GET, UL_BC_BUFFER | UL_BC_IN);
  216. AmountInBuffer = BufferState.BytesInINBuffer;
  217. if(pPort->IsrWaitMask)
  218. {
  219. // Check to see if we should note the receive character
  220. if(pPort->IsrWaitMask & SERIAL_EV_RXCHAR)
  221. pPort->HistoryMask |= SERIAL_EV_RXCHAR;
  222. // If we've become 80% full on this character and this is an interesting event, note it.
  223. if((pPort->IsrWaitMask & SERIAL_EV_RX80FULL) && (AmountInBuffer >= pPort->BufferSizePt8))
  224. pPort->HistoryMask |= SERIAL_EV_RX80FULL;
  225. #ifndef USE_HW_TO_DETECT_CHAR
  226. // if we detected the special char
  227. if((pPort->IsrWaitMask & SERIAL_EV_RXFLAG) && (StatusFlags & UL_RS_SPECIAL_CHAR_DETECTED))
  228. pPort->HistoryMask |= SERIAL_EV_RXFLAG;
  229. #endif
  230. if(pPort->IrpMaskLocation && pPort->HistoryMask)
  231. {
  232. *pPort->IrpMaskLocation = pPort->HistoryMask;
  233. pPort->IrpMaskLocation = NULL;
  234. pPort->HistoryMask = 0;
  235. pPort->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
  236. // Mark IRP as about to complete normally to prevent cancel & timer DPCs
  237. // from doing so before DPC is allowed to run.
  238. //SERIAL_SET_REFERENCE(pPort->CurrentWaitIrp, SERIAL_REF_COMPLETING);
  239. KeInsertQueueDpc(&pPort->CommWaitDpc, NULL, NULL);
  240. }
  241. }
  242. // If we have a current Read IRP.
  243. if(pPort->CurrentReadIrp && pPort->NumberNeededForRead)
  244. {
  245. // If our ISR currently owns the IRP the we are allowed to do something with it,
  246. // But we only need to do something if we need to make room in the buffer
  247. // or we have enough bytes in the buffer to complete the current read IRP.
  248. if((SERIAL_REFERENCE_COUNT(pPort->CurrentReadIrp) & SERIAL_REF_ISR)
  249. && ((AmountInBuffer >= pPort->BufferSizePt8)
  250. || (AmountInBuffer >= pPort->NumberNeededForRead)))
  251. {
  252. ULONG NumberOfBytes = 0;
  253. NumberOfBytes = pPort->pUartLib->UL_ReadData_XXXX(pPort->pUart,
  254. (PUCHAR)(pPort->CurrentReadIrp->AssociatedIrp.SystemBuffer)
  255. + pPort->CurrentReadIrp->IoStatus.Information,
  256. IoGetCurrentIrpStackLocation(pPort->CurrentReadIrp)->Parameters.Read.Length
  257. - pPort->CurrentReadIrp->IoStatus.Information);
  258. if(NumberOfBytes > pPort->NumberNeededForRead)
  259. pPort->NumberNeededForRead = 0;
  260. else
  261. pPort->NumberNeededForRead -= NumberOfBytes;
  262. pPort->CurrentReadIrp->IoStatus.Information += NumberOfBytes;
  263. if(pPort->NumberNeededForRead == 0)
  264. {
  265. ASSERT(pPort->CurrentReadIrp->IoStatus.Information
  266. == IoGetCurrentIrpStackLocation(pPort->CurrentReadIrp)->Parameters.Read.Length);
  267. // Mark IRP as about to complete normally to prevent cancel & timer DPCs
  268. // from doing so before DPC is allowed to run.
  269. SERIAL_SET_REFERENCE(pPort->CurrentReadIrp, SERIAL_REF_COMPLETING);
  270. KeInsertQueueDpc(&pPort->CompleteReadDpc, NULL, NULL);
  271. }
  272. }
  273. }
  274. }
  275. }
  276. // Service transmitt and transmitt empty interrupts.
  277. if((IntsPending & UL_IP_TX) || (IntsPending & UL_IP_TX_EMPTY))
  278. {
  279. // No need to clear the INT it was already cleared by reading the IIR.
  280. DWORD BytesRemaining = pPort->pUartLib->UL_OutputData_XXXX(pUart); // Output some bytes
  281. // If we have a current Write Immediate IRP.
  282. if(pPort->CurrentImmediateIrp)
  283. {
  284. if(SERIAL_REFERENCE_COUNT(pPort->CurrentImmediateIrp) & SERIAL_REF_ISR)
  285. {
  286. if(pPort->TransmitImmediate == TRUE)
  287. {
  288. // Check if the byte has been sent.
  289. if(pPort->pUartLib->UL_ImmediateByte_XXXX(pUart, &pPort->ImmediateIndex, UL_IM_OP_STATUS) == UL_IM_NO_BYTE_TO_SEND)
  290. {
  291. pPort->TransmitImmediate = FALSE;
  292. pPort->EmptiedTransmit = TRUE;
  293. pPort->PerfStats.TransmittedCount++; // Increment Tx Counter
  294. #ifdef WMI_SUPPORT
  295. pPort->WmiPerfData.TransmittedCount++;
  296. #endif
  297. // Mark IRP as about to complete normally to prevent cancel & timer DPCs
  298. // from doing so before DPC is allowed to run.
  299. SERIAL_SET_REFERENCE(pPort->CurrentImmediateIrp, SERIAL_REF_COMPLETING);
  300. // Ask to complete the IRP.
  301. KeInsertQueueDpc(&pPort->CompleteImmediateDpc, NULL, NULL);
  302. }
  303. }
  304. }
  305. }
  306. // If we have a current Write IRP.
  307. if(pPort->CurrentWriteIrp && pPort->WriteLength)
  308. {
  309. //
  310. // Even though all of the characters being
  311. // sent haven't all been sent, this variable
  312. // will be checked when the transmit queue is
  313. // empty. If it is still true and there is a
  314. // wait on the transmit queue being empty then
  315. // we know we finished transmitting all characters
  316. // following the initiation of the wait since
  317. // the code that initiates the wait will set
  318. // this variable to false.
  319. //
  320. // One reason it could be false is that
  321. // the writes were cancelled before they
  322. // actually started, or that the writes
  323. // failed due to timeouts. This variable
  324. // basically says a character was written
  325. // by the isr at some point following the
  326. // initiation of the wait.
  327. //
  328. if(SERIAL_REFERENCE_COUNT(pPort->CurrentWriteIrp) & SERIAL_REF_ISR)
  329. {
  330. if(pPort->WriteLength > BytesRemaining)
  331. {
  332. pPort->PerfStats.TransmittedCount += (pPort->WriteLength - BytesRemaining); // Increment Tx Counter
  333. #ifdef WMI_SUPPORT
  334. pPort->WmiPerfData.TransmittedCount += (pPort->WriteLength - BytesRemaining);
  335. #endif
  336. }
  337. else
  338. {
  339. pPort->PerfStats.TransmittedCount += pPort->WriteLength; // Increment Tx Counter
  340. #ifdef WMI_SUPPORT
  341. pPort->WmiPerfData.TransmittedCount += pPort->WriteLength;
  342. #endif
  343. }
  344. pPort->WriteLength = BytesRemaining;
  345. pPort->EmptiedTransmit = TRUE;
  346. if(pPort->WriteLength == 0) // If write is complete - lets complete the IRP
  347. {
  348. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(pPort->CurrentWriteIrp);
  349. // No More characters left. This write is complete. Take care when
  350. // updating the information field, we could have an xoff
  351. // counter masquerading as a write irp.
  352. pPort->CurrentWriteIrp->IoStatus.Information
  353. = (IrpSp->MajorFunction == IRP_MJ_WRITE)
  354. ? (IrpSp->Parameters.Write.Length) : (1);
  355. // Mark IRP as about to complete normally to prevent cancel & timer DPCs
  356. // from doing so before DPC is allowed to run.
  357. SERIAL_SET_REFERENCE(pPort->CurrentWriteIrp, SERIAL_REF_COMPLETING);
  358. KeInsertQueueDpc(&pPort->CompleteWriteDpc, NULL, NULL);
  359. }
  360. }
  361. }
  362. }
  363. // Service modem interrupts.
  364. if(IntsPending & UL_IP_MODEM)
  365. {
  366. SerialHandleModemUpdate(pPort, FALSE);
  367. }
  368. // Save a pointer to the UART serviced so it can be the first UART serviced
  369. // in the list the next time the ISR is called.
  370. //pCard->pFirstUart = pUart;
  371. ServicedAnInterrupt = TRUE;
  372. }
  373. }
  374. return ServicedAnInterrupt;
  375. }