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.

582 lines
13 KiB

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