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.

563 lines
12 KiB

  1. /*++
  2. Copyright (c) 1991, 1992, 1993 - 1997 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. --*/
  13. #include "precomp.h"
  14. VOID
  15. SerialGetNextImmediate(
  16. IN PIRP *CurrentOpIrp,
  17. IN PLIST_ENTRY QueueToProcess,
  18. IN PIRP *NewIrp,
  19. IN BOOLEAN CompleteCurrent,
  20. IN PSERIAL_DEVICE_EXTENSION Extension
  21. );
  22. VOID
  23. SerialCancelImmediate(
  24. IN PDEVICE_OBJECT DeviceObject,
  25. IN PIRP Irp
  26. );
  27. BOOLEAN
  28. SerialGiveImmediateToIsr(
  29. IN PVOID Context
  30. );
  31. BOOLEAN
  32. SerialGrabImmediateFromIsr(
  33. IN PVOID Context
  34. );
  35. BOOLEAN
  36. SerialGiveImmediateToIsr(
  37. IN PVOID Context
  38. );
  39. BOOLEAN
  40. SerialGrabImmediateFromIsr(
  41. IN PVOID Context
  42. );
  43. #ifdef ALLOC_PRAGMA
  44. #pragma alloc_text(PAGESER,SerialStartImmediate)
  45. #pragma alloc_text(PAGESER,SerialGetNextImmediate)
  46. #pragma alloc_text(PAGESER,SerialCancelImmediate)
  47. #pragma alloc_text(PAGESER,SerialGiveImmediateToIsr)
  48. #pragma alloc_text(PAGESER,SerialGrabImmediateFromIsr)
  49. #endif
  50. VOID
  51. SerialStartImmediate(
  52. IN PSERIAL_DEVICE_EXTENSION Extension
  53. )
  54. /*++
  55. Routine Description:
  56. This routine will calculate the timeouts needed for the
  57. write. It will then hand the irp off to the isr. It
  58. will need to be careful incase the irp has been canceled.
  59. Arguments:
  60. Extension - A pointer to the serial device extension.
  61. Return Value:
  62. None.
  63. --*/
  64. {
  65. KIRQL OldIrql;
  66. LARGE_INTEGER TotalTime;
  67. BOOLEAN UseATimer;
  68. SERIAL_TIMEOUTS Timeouts;
  69. SERIAL_LOCKED_PAGED_CODE();
  70. SerialDump(SERTRACECALLS, ("SERIAL: SerialStartImmediate\n"));
  71. UseATimer = FALSE;
  72. Extension->CurrentImmediateIrp->IoStatus.Status = STATUS_PENDING;
  73. IoMarkIrpPending(Extension->CurrentImmediateIrp);
  74. //
  75. // Calculate the timeout value needed for the
  76. // request. Note that the values stored in the
  77. // timeout record are in milliseconds. Note that
  78. // if the timeout values are zero then we won't start
  79. // the timer.
  80. //
  81. KeAcquireSpinLock(
  82. &Extension->ControlLock,
  83. &OldIrql
  84. );
  85. Timeouts = Extension->Timeouts;
  86. KeReleaseSpinLock(
  87. &Extension->ControlLock,
  88. OldIrql
  89. );
  90. if (Timeouts.WriteTotalTimeoutConstant ||
  91. Timeouts.WriteTotalTimeoutMultiplier) {
  92. UseATimer = TRUE;
  93. //
  94. // We have some timer values to calculate.
  95. //
  96. TotalTime.QuadPart = (LONGLONG)((ULONG)Timeouts.WriteTotalTimeoutMultiplier);
  97. TotalTime.QuadPart += Timeouts.WriteTotalTimeoutConstant;
  98. TotalTime.QuadPart *= -10000;
  99. }
  100. //
  101. // As the irp might be going to the isr, this is a good time
  102. // to initialize the reference count.
  103. //
  104. SERIAL_INIT_REFERENCE(Extension->CurrentImmediateIrp);
  105. //
  106. // We need to see if this irp should be canceled.
  107. //
  108. IoAcquireCancelSpinLock(&OldIrql);
  109. if (Extension->CurrentImmediateIrp->Cancel) {
  110. PIRP OldIrp = Extension->CurrentImmediateIrp;
  111. Extension->CurrentImmediateIrp = NULL;
  112. IoReleaseCancelSpinLock(OldIrql);
  113. OldIrp->IoStatus.Status = STATUS_CANCELLED;
  114. OldIrp->IoStatus.Information = 0;
  115. SerialDump(
  116. SERIRPPATH,
  117. ("SERIAL: Complete Irp: %x\n",OldIrp)
  118. );
  119. SerialCompleteRequest(Extension, OldIrp, 0);
  120. } else {
  121. //
  122. // We give the irp to to the isr to write out.
  123. // We set a cancel routine that knows how to
  124. // grab the current write away from the isr.
  125. //
  126. IoSetCancelRoutine(
  127. Extension->CurrentImmediateIrp,
  128. SerialCancelImmediate
  129. );
  130. //
  131. // Since the cancel routine knows about the irp we
  132. // increment the reference count.
  133. //
  134. SERIAL_SET_REFERENCE(
  135. Extension->CurrentImmediateIrp,
  136. SERIAL_REF_CANCEL
  137. );
  138. if (UseATimer) {
  139. SerialSetTimer(
  140. &Extension->ImmediateTotalTimer,
  141. TotalTime,
  142. &Extension->TotalImmediateTimeoutDpc,
  143. Extension
  144. );
  145. //
  146. // Since the timer knows about the irp we increment
  147. // the reference count.
  148. //
  149. SERIAL_SET_REFERENCE(
  150. Extension->CurrentImmediateIrp,
  151. SERIAL_REF_TOTAL_TIMER
  152. );
  153. }
  154. KeSynchronizeExecution(
  155. Extension->Interrupt,
  156. SerialGiveImmediateToIsr,
  157. Extension
  158. );
  159. IoReleaseCancelSpinLock(OldIrql);
  160. }
  161. }
  162. VOID
  163. SerialCompleteImmediate(
  164. IN PKDPC Dpc,
  165. IN PVOID DeferredContext,
  166. IN PVOID SystemContext1,
  167. IN PVOID SystemContext2
  168. )
  169. {
  170. PSERIAL_DEVICE_EXTENSION Extension = DeferredContext;
  171. KIRQL OldIrql;
  172. UNREFERENCED_PARAMETER(SystemContext1);
  173. UNREFERENCED_PARAMETER(SystemContext2);
  174. SerialDump(SERTRACECALLS, ("SERIAL: SerialCompleteImmediate\n"));
  175. IoAcquireCancelSpinLock(&OldIrql);
  176. SerialTryToCompleteCurrent(
  177. Extension,
  178. NULL,
  179. OldIrql,
  180. STATUS_SUCCESS,
  181. &Extension->CurrentImmediateIrp,
  182. NULL,
  183. NULL,
  184. &Extension->ImmediateTotalTimer,
  185. NULL,
  186. SerialGetNextImmediate,
  187. SERIAL_REF_ISR
  188. );
  189. SerialDpcEpilogue(Extension, Dpc);
  190. }
  191. VOID
  192. SerialTimeoutImmediate(
  193. IN PKDPC Dpc,
  194. IN PVOID DeferredContext,
  195. IN PVOID SystemContext1,
  196. IN PVOID SystemContext2
  197. )
  198. {
  199. PSERIAL_DEVICE_EXTENSION Extension = DeferredContext;
  200. KIRQL OldIrql;
  201. UNREFERENCED_PARAMETER(SystemContext1);
  202. UNREFERENCED_PARAMETER(SystemContext2);
  203. SerialDump(SERTRACECALLS, ("SERIAL: SerialTimeoutImmediate\n"));
  204. IoAcquireCancelSpinLock(&OldIrql);
  205. SerialTryToCompleteCurrent(
  206. Extension,
  207. SerialGrabImmediateFromIsr,
  208. OldIrql,
  209. STATUS_TIMEOUT,
  210. &Extension->CurrentImmediateIrp,
  211. NULL,
  212. NULL,
  213. &Extension->ImmediateTotalTimer,
  214. NULL,
  215. SerialGetNextImmediate,
  216. SERIAL_REF_TOTAL_TIMER
  217. );
  218. SerialDpcEpilogue(Extension, Dpc);
  219. }
  220. VOID
  221. SerialGetNextImmediate(
  222. IN PIRP *CurrentOpIrp,
  223. IN PLIST_ENTRY QueueToProcess,
  224. IN PIRP *NewIrp,
  225. IN BOOLEAN CompleteCurrent,
  226. IN PSERIAL_DEVICE_EXTENSION Extension
  227. )
  228. /*++
  229. Routine Description:
  230. This routine is used to complete the current immediate
  231. irp. Even though the current immediate will always
  232. be completed and there is no queue associated with it,
  233. we use this routine so that we can try to satisfy
  234. a wait for transmit queue empty event.
  235. Arguments:
  236. CurrentOpIrp - Pointer to the pointer that points to the
  237. current write irp. This should point
  238. to CurrentImmediateIrp.
  239. QueueToProcess - Always NULL.
  240. NewIrp - Always NULL on exit to this routine.
  241. CompleteCurrent - Should always be true for this routine.
  242. Return Value:
  243. None.
  244. --*/
  245. {
  246. KIRQL OldIrql;
  247. // PSERIAL_DEVICE_EXTENSION Extension = CONTAINING_RECORD(
  248. // CurrentOpIrp,
  249. // SERIAL_DEVICE_EXTENSION,
  250. // CurrentImmediateIrp
  251. // );
  252. PIRP OldIrp = *CurrentOpIrp;
  253. UNREFERENCED_PARAMETER(QueueToProcess);
  254. UNREFERENCED_PARAMETER(CompleteCurrent);
  255. SERIAL_LOCKED_PAGED_CODE();
  256. IoAcquireCancelSpinLock(&OldIrql);
  257. ASSERT(Extension->TotalCharsQueued >= 1);
  258. Extension->TotalCharsQueued--;
  259. *CurrentOpIrp = NULL;
  260. *NewIrp = NULL;
  261. KeSynchronizeExecution(
  262. Extension->Interrupt,
  263. SerialProcessEmptyTransmit,
  264. Extension
  265. );
  266. IoReleaseCancelSpinLock(OldIrql);
  267. SerialDump(
  268. SERIRPPATH,
  269. ("SERIAL: Complete Irp: %x\n",OldIrp)
  270. );
  271. SerialCompleteRequest(Extension, OldIrp, IO_SERIAL_INCREMENT);
  272. }
  273. VOID
  274. SerialCancelImmediate(
  275. IN PDEVICE_OBJECT DeviceObject,
  276. IN PIRP Irp
  277. )
  278. /*++
  279. Routine Description:
  280. This routine is used to cancel a irp that is waiting on
  281. a comm event.
  282. Arguments:
  283. DeviceObject - Pointer to the device object for this device
  284. Irp - Pointer to the IRP for the current request
  285. Return Value:
  286. None.
  287. --*/
  288. {
  289. PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
  290. SERIAL_LOCKED_PAGED_CODE();
  291. SerialTryToCompleteCurrent(
  292. Extension,
  293. SerialGrabImmediateFromIsr,
  294. Irp->CancelIrql,
  295. STATUS_CANCELLED,
  296. &Extension->CurrentImmediateIrp,
  297. NULL,
  298. NULL,
  299. &Extension->ImmediateTotalTimer,
  300. NULL,
  301. SerialGetNextImmediate,
  302. SERIAL_REF_CANCEL
  303. );
  304. }
  305. BOOLEAN
  306. SerialGiveImmediateToIsr(
  307. IN PVOID Context
  308. )
  309. /*++
  310. Routine Description:
  311. Try to start off the write by slipping it in behind
  312. a transmit immediate char, or if that isn't available
  313. and the transmit holding register is empty, "tickle"
  314. the UART into interrupting with a transmit buffer
  315. empty.
  316. NOTE: This routine is called by KeSynchronizeExecution.
  317. NOTE: This routine assumes that it is called with the
  318. cancel spin lock held.
  319. Arguments:
  320. Context - Really a pointer to the device extension.
  321. Return Value:
  322. This routine always returns FALSE.
  323. --*/
  324. {
  325. PSERIAL_DEVICE_EXTENSION Extension = Context;
  326. SERIAL_LOCKED_PAGED_CODE();
  327. Extension->TransmitImmediate = TRUE;
  328. Extension->ImmediateChar =
  329. *((UCHAR *)
  330. (Extension->CurrentImmediateIrp->AssociatedIrp.SystemBuffer));
  331. //
  332. // The isr now has a reference to the irp.
  333. //
  334. SERIAL_SET_REFERENCE(
  335. Extension->CurrentImmediateIrp,
  336. SERIAL_REF_ISR
  337. );
  338. //
  339. // Check first to see if a write is going on. If
  340. // there is then we'll just slip in during the write.
  341. //
  342. if (!Extension->WriteLength) {
  343. //
  344. // If there is no normal write transmitting then we
  345. // will "re-enable" the transmit holding register empty
  346. // interrupt. The 8250 family of devices will always
  347. // signal a transmit holding register empty interrupt
  348. // *ANY* time this bit is set to one. By doing things
  349. // this way we can simply use the normal interrupt code
  350. // to start off this write.
  351. //
  352. // We've been keeping track of whether the transmit holding
  353. // register is empty so it we only need to do this
  354. // if the register is empty.
  355. //
  356. if (Extension->HoldingEmpty) {
  357. DISABLE_ALL_INTERRUPTS(Extension->Controller);
  358. ENABLE_ALL_INTERRUPTS(Extension->Controller);
  359. }
  360. }
  361. return FALSE;
  362. }
  363. BOOLEAN
  364. SerialGrabImmediateFromIsr(
  365. IN PVOID Context
  366. )
  367. /*++
  368. Routine Description:
  369. This routine is used to grab the current irp, which could be timing
  370. out or canceling, from the ISR
  371. NOTE: This routine is being called from KeSynchronizeExecution.
  372. NOTE: This routine assumes that the cancel spin lock is held
  373. when this routine is called.
  374. Arguments:
  375. Context - Really a pointer to the device extension.
  376. Return Value:
  377. Always false.
  378. --*/
  379. {
  380. PSERIAL_DEVICE_EXTENSION Extension = Context;
  381. SERIAL_LOCKED_PAGED_CODE();
  382. if (Extension->TransmitImmediate) {
  383. Extension->TransmitImmediate = FALSE;
  384. //
  385. // Since the isr no longer references this irp, we can
  386. // decrement it's reference count.
  387. //
  388. SERIAL_CLEAR_REFERENCE(
  389. Extension->CurrentImmediateIrp,
  390. SERIAL_REF_ISR
  391. );
  392. }
  393. return FALSE;
  394. }