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.

377 lines
10 KiB

  1. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Copyright (c) 1991, 1992, 1993 Microsoft Corporation
  3. Module Name:
  4. immediat.c
  5. Abstract:
  6. This module contains the code that is very specific to transmit
  7. immediate character operations in the 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. // Prototypes
  16. VOID SerialGetNextImmediate(IN PPORT_DEVICE_EXTENSION pPort,
  17. IN PIRP *CurrentOpIrp,
  18. IN PLIST_ENTRY QueueToProcess,
  19. IN PIRP *NewIrp,
  20. IN BOOLEAN CompleteCurrent);
  21. VOID SerialCancelImmediate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
  22. BOOLEAN SerialGiveImmediateToIsr(IN PVOID Context);
  23. BOOLEAN SerialGrabImmediateFromIsr(IN PVOID Context);
  24. BOOLEAN SerialGiveImmediateToIsr(IN PVOID Context);
  25. BOOLEAN SerialGrabImmediateFromIsr(IN PVOID Context);
  26. // End of prototypes
  27. // Paging
  28. #ifdef ALLOC_PRAGMA
  29. #endif
  30. VOID
  31. SerialStartImmediate(IN PPORT_DEVICE_EXTENSION pPort)
  32. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  33. Routine Description:
  34. This routine will calculate the timeouts needed for the
  35. write. It will then hand the irp off to the isr. It
  36. will need to be careful incase the irp has been canceled.
  37. Arguments:
  38. Extension - A pointer to the serial device extension.
  39. Return Value:
  40. None.
  41. -----------------------------------------------------------------------------*/
  42. {
  43. KIRQL OldIrql;
  44. LARGE_INTEGER TotalTime;
  45. BOOLEAN UseATimer;
  46. SERIAL_TIMEOUTS Timeouts;
  47. UseATimer = FALSE;
  48. pPort->CurrentImmediateIrp->IoStatus.Status = STATUS_PENDING;
  49. IoMarkIrpPending(pPort->CurrentImmediateIrp);
  50. //
  51. // Calculate the timeout value needed for the
  52. // request. Note that the values stored in the
  53. // timeout record are in milliseconds. Note that
  54. // if the timeout values are zero then we won't start
  55. // the timer.
  56. //
  57. KeAcquireSpinLock(&pPort->ControlLock, &OldIrql);
  58. Timeouts = pPort->Timeouts;
  59. KeReleaseSpinLock(&pPort->ControlLock, OldIrql);
  60. if(Timeouts.WriteTotalTimeoutConstant || Timeouts.WriteTotalTimeoutMultiplier)
  61. {
  62. UseATimer = TRUE;
  63. // We have some timer values to calculate.
  64. TotalTime.QuadPart = (LONGLONG)((ULONG)Timeouts.WriteTotalTimeoutMultiplier);
  65. TotalTime.QuadPart += Timeouts.WriteTotalTimeoutConstant;
  66. TotalTime.QuadPart *= -10000;
  67. }
  68. //
  69. // As the irp might be going to the isr, this is a good time
  70. // to initialize the reference count.
  71. //
  72. SERIAL_INIT_REFERENCE(pPort->CurrentImmediateIrp);
  73. //
  74. // We need to see if this irp should be canceled.
  75. //
  76. IoAcquireCancelSpinLock(&OldIrql);
  77. if(pPort->CurrentImmediateIrp->Cancel)
  78. {
  79. PIRP OldIrp = pPort->CurrentImmediateIrp;
  80. pPort->CurrentImmediateIrp = NULL;
  81. IoReleaseCancelSpinLock(OldIrql);
  82. OldIrp->IoStatus.Status = STATUS_CANCELLED;
  83. OldIrp->IoStatus.Information = 0;
  84. SerialDump(SERIRPPATH,("Complete Irp: %x\n",OldIrp));
  85. SpxIRPCounter(pPort, OldIrp, IRP_COMPLETED); // Increment counter for performance stats.
  86. IoCompleteRequest(OldIrp, 0);
  87. }
  88. else
  89. {
  90. //
  91. // We give the irp to to the isr to write out.
  92. // We set a cancel routine that knows how to
  93. // grab the current write away from the isr.
  94. //
  95. IoSetCancelRoutine(pPort->CurrentImmediateIrp, SerialCancelImmediate);
  96. //
  97. // Since the cancel routine knows about the irp we increment the reference count.
  98. //
  99. SERIAL_SET_REFERENCE(pPort->CurrentImmediateIrp, SERIAL_REF_CANCEL);
  100. if(UseATimer)
  101. {
  102. KeSetTimer(&pPort->ImmediateTotalTimer, TotalTime, &pPort->TotalImmediateTimeoutDpc);
  103. // Since the timer knows about the irp we increment the reference count.
  104. SERIAL_SET_REFERENCE(pPort->CurrentImmediateIrp, SERIAL_REF_TOTAL_TIMER);
  105. }
  106. KeSynchronizeExecution(pPort->Interrupt, SerialGiveImmediateToIsr, pPort);
  107. IoReleaseCancelSpinLock(OldIrql);
  108. }
  109. }
  110. VOID
  111. SerialCompleteImmediate(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemContext1, IN PVOID SystemContext2)
  112. {
  113. PPORT_DEVICE_EXTENSION pPort = DeferredContext;
  114. KIRQL OldIrql;
  115. UNREFERENCED_PARAMETER(Dpc);
  116. UNREFERENCED_PARAMETER(SystemContext1);
  117. UNREFERENCED_PARAMETER(SystemContext2);
  118. IoAcquireCancelSpinLock(&OldIrql);
  119. // Clear the normal complete reference.
  120. SERIAL_CLEAR_REFERENCE(pPort->CurrentImmediateIrp, SERIAL_REF_COMPLETING);
  121. SerialTryToCompleteCurrent( pPort, NULL, OldIrql, STATUS_SUCCESS, &pPort->CurrentImmediateIrp,
  122. NULL, NULL, &pPort->ImmediateTotalTimer, NULL, SerialGetNextImmediate,
  123. SERIAL_REF_ISR);
  124. }
  125. VOID
  126. SerialTimeoutImmediate(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemContext1, IN PVOID SystemContext2)
  127. {
  128. PPORT_DEVICE_EXTENSION pPort = DeferredContext;
  129. KIRQL OldIrql;
  130. UNREFERENCED_PARAMETER(Dpc);
  131. UNREFERENCED_PARAMETER(SystemContext1);
  132. UNREFERENCED_PARAMETER(SystemContext2);
  133. IoAcquireCancelSpinLock(&OldIrql);
  134. SerialTryToCompleteCurrent( pPort, SerialGrabImmediateFromIsr, OldIrql, STATUS_TIMEOUT,
  135. &pPort->CurrentImmediateIrp, NULL, NULL, &pPort->ImmediateTotalTimer,
  136. NULL, SerialGetNextImmediate, SERIAL_REF_TOTAL_TIMER);
  137. }
  138. VOID
  139. SerialGetNextImmediate(IN PPORT_DEVICE_EXTENSION pPort,
  140. IN PIRP *CurrentOpIrp,
  141. IN PLIST_ENTRY QueueToProcess,
  142. IN PIRP *NewIrp,
  143. IN BOOLEAN CompleteCurrent)
  144. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  145. Routine Description:
  146. This routine is used to complete the current immediate
  147. irp. Even though the current immediate will always
  148. be completed and there is no queue associated with it,
  149. we use this routine so that we can try to satisfy
  150. a wait for transmit queue empty event.
  151. Arguments:
  152. CurrentOpIrp - Pointer to the pointer that points to the
  153. current write irp. This should point
  154. to CurrentImmediateIrp.
  155. QueueToProcess - Always NULL.
  156. NewIrp - Always NULL on exit to this routine.
  157. CompleteCurrent - Should always be true for this routine.
  158. Return Value:
  159. None.
  160. -----------------------------------------------------------------------------*/
  161. {
  162. KIRQL OldIrql;
  163. PIRP OldIrp = *CurrentOpIrp;
  164. UNREFERENCED_PARAMETER(QueueToProcess);
  165. UNREFERENCED_PARAMETER(CompleteCurrent);
  166. pPort = CONTAINING_RECORD(CurrentOpIrp, PORT_DEVICE_EXTENSION, CurrentImmediateIrp);
  167. IoAcquireCancelSpinLock(&OldIrql);
  168. ASSERT(pPort->TotalCharsQueued >= 1);
  169. pPort->TotalCharsQueued--;
  170. *CurrentOpIrp = NULL;
  171. *NewIrp = NULL;
  172. KeSynchronizeExecution(pPort->Interrupt, SerialProcessEmptyTransmit, pPort);
  173. IoReleaseCancelSpinLock(OldIrql);
  174. SerialDump(SERIRPPATH,("SERIAL: Complete Irp: %x\n", OldIrp));
  175. SpxIRPCounter(pPort, OldIrp, IRP_COMPLETED); // Increment counter for performance stats.
  176. IoCompleteRequest(OldIrp, IO_SERIAL_INCREMENT);
  177. }
  178. VOID
  179. SerialCancelImmediate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  180. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  181. Routine Description:
  182. This routine is used to cancel a irp that is waiting on
  183. a comm event.
  184. Arguments:
  185. DeviceObject - Pointer to the device object for this device
  186. Irp - Pointer to the IRP for the current request
  187. Return Value:
  188. None.
  189. -----------------------------------------------------------------------------*/
  190. {
  191. PPORT_DEVICE_EXTENSION pPort = DeviceObject->DeviceExtension;
  192. SerialTryToCompleteCurrent( pPort, SerialGrabImmediateFromIsr, Irp->CancelIrql, STATUS_CANCELLED,
  193. &pPort->CurrentImmediateIrp, NULL, NULL, &pPort->ImmediateTotalTimer,
  194. NULL, SerialGetNextImmediate, SERIAL_REF_CANCEL);
  195. }
  196. BOOLEAN
  197. SerialGiveImmediateToIsr(IN PVOID Context)
  198. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  199. Routine Description:
  200. Try to start off the write by slipping it in behind
  201. a transmit immediate char, or if that isn't available
  202. and the transmit holding register is empty, "tickle"
  203. the UART into interrupting with a transmit buffer
  204. empty.
  205. NOTE: This routine is called by KeSynchronizeExecution.
  206. NOTE: This routine assumes that it is called with the
  207. cancel spin lock held.
  208. Arguments:
  209. Context - Really a pointer to the device extension.
  210. Return Value:
  211. This routine always returns FALSE.
  212. -----------------------------------------------------------------------------*/
  213. {
  214. PPORT_DEVICE_EXTENSION pPort = Context;
  215. pPort->TransmitImmediate = TRUE;
  216. pPort->ImmediateIndex = *((UCHAR *)(pPort->CurrentImmediateIrp->AssociatedIrp.SystemBuffer));
  217. // The isr now has a reference to the irp.
  218. SERIAL_SET_REFERENCE(pPort->CurrentImmediateIrp, SERIAL_REF_ISR);
  219. pPort->pUartLib->UL_ImmediateByte_XXXX(pPort->pUart, &pPort->ImmediateIndex, UL_IM_OP_WRITE);
  220. return FALSE;
  221. }
  222. BOOLEAN
  223. SerialGrabImmediateFromIsr(IN PVOID Context)
  224. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  225. Routine Description:
  226. This routine is used to grab the current irp, which could be timing
  227. out or canceling, from the ISR
  228. NOTE: This routine is being called from KeSynchronizeExecution.
  229. NOTE: This routine assumes that the cancel spin lock is held
  230. when this routine is called.
  231. Arguments:
  232. Context - Really a pointer to the device extension.
  233. Return Value:
  234. Always false.
  235. -----------------------------------------------------------------------------*/
  236. {
  237. PPORT_DEVICE_EXTENSION pPort = Context;
  238. if(pPort->TransmitImmediate)
  239. {
  240. // Since the isr no longer references this irp, we can
  241. // decrement it's reference count.
  242. SERIAL_CLEAR_REFERENCE(pPort->CurrentImmediateIrp, SERIAL_REF_ISR);
  243. pPort->TransmitImmediate = FALSE;
  244. pPort->pUartLib->UL_ImmediateByte_XXXX(pPort->pUart, &pPort->ImmediateIndex, UL_IM_OP_CANCEL);
  245. pPort->ImmediateIndex = 0;
  246. }
  247. return FALSE;
  248. }