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.

687 lines
20 KiB

  1. /*--------------------------------------------------------------------------
  2. *
  3. * Copyright (C) Cyclades Corporation, 1997-2001.
  4. * All rights reserved.
  5. *
  6. * Cyclades-Z Port Driver
  7. *
  8. * This file: cyzmask.c
  9. *
  10. * Description: This module contains the code related to get/set/wait
  11. * on event mask operations in the Cyclades-Z 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. BOOLEAN
  31. CyzGrabWaitFromIsr(
  32. IN PVOID Context
  33. );
  34. BOOLEAN
  35. CyzGiveWaitToIsr(
  36. IN PVOID Context
  37. );
  38. BOOLEAN
  39. CyzFinishOldWait(
  40. IN PVOID Context
  41. );
  42. #ifdef ALLOC_PRAGMA
  43. #pragma alloc_text(PAGESER,CyzStartMask)
  44. #pragma alloc_text(PAGESER,CyzCancelWait)
  45. #pragma alloc_text(PAGESER,CyzGrabWaitFromIsr)
  46. #pragma alloc_text(PAGESER,CyzGiveWaitToIsr)
  47. #pragma alloc_text(PAGESER,CyzFinishOldWait)
  48. #endif
  49. NTSTATUS
  50. CyzStartMask(
  51. IN PCYZ_DEVICE_EXTENSION Extension
  52. )
  53. /*++
  54. Routine Description:
  55. This routine is used to process the set mask and wait
  56. mask ioctls. Calls to this routine are serialized by
  57. placing irps in the list under the protection of the
  58. cancel spin lock.
  59. Arguments:
  60. Extension - A pointer to the serial device extension.
  61. Return Value:
  62. Will return pending for everything put the first
  63. request that we actually process. Even in that
  64. case it will return pending unless it can complete
  65. it right away.
  66. --*/
  67. {
  68. #ifdef POLL
  69. KIRQL pollIrql;
  70. #endif
  71. //
  72. // The current stack location. This contains much of the
  73. // information we need to process this particular request.
  74. //
  75. PIO_STACK_LOCATION IrpSp;
  76. PIRP NewIrp;
  77. BOOLEAN SetFirstStatus = FALSE;
  78. NTSTATUS FirstStatus;
  79. CYZ_LOCKED_PAGED_CODE();
  80. CyzDbgPrintEx(CYZDIAG3, "In CyzStartMask\n");
  81. ASSERT(Extension->CurrentMaskIrp);
  82. do {
  83. CyzDbgPrintEx(CYZDIAG4, "STARTMASK - CurrentMaskIrp: %x\n",
  84. Extension->CurrentMaskIrp);
  85. IrpSp = IoGetCurrentIrpStackLocation(Extension->CurrentMaskIrp);
  86. ASSERT((IrpSp->Parameters.DeviceIoControl.IoControlCode ==
  87. IOCTL_SERIAL_WAIT_ON_MASK) ||
  88. (IrpSp->Parameters.DeviceIoControl.IoControlCode ==
  89. IOCTL_SERIAL_SET_WAIT_MASK));
  90. if (IrpSp->Parameters.DeviceIoControl.IoControlCode ==
  91. IOCTL_SERIAL_SET_WAIT_MASK) {
  92. CyzDbgPrintEx(CYZDIAG4, "%x is a SETMASK irp\n",
  93. Extension->CurrentMaskIrp);
  94. //
  95. // Complete the old wait if there is one.
  96. //
  97. #ifdef POLL
  98. KeAcquireSpinLock(&Extension->PollLock,&pollIrql);
  99. CyzFinishOldWait(Extension);
  100. KeReleaseSpinLock(&Extension->PollLock,pollIrql);
  101. #else
  102. KeSynchronizeExecution(
  103. Extension->Interrupt,
  104. CyzFinishOldWait,
  105. Extension
  106. );
  107. #endif
  108. //
  109. // Any current waits should be on its way to completion
  110. // at this point. There certainly shouldn't be any
  111. // irp mask location.
  112. //
  113. ASSERT(!Extension->IrpMaskLocation);
  114. Extension->CurrentMaskIrp->IoStatus.Status = STATUS_SUCCESS;
  115. if (!SetFirstStatus) {
  116. CyzDbgPrintEx(CYZDIAG4, "%x was the first irp processed by "
  117. "this\n"
  118. "------- invocation of startmask\n",
  119. Extension->CurrentMaskIrp);
  120. FirstStatus = STATUS_SUCCESS;
  121. SetFirstStatus = TRUE;
  122. }
  123. //
  124. // The following call will also cause the current
  125. // call to be completed.
  126. //
  127. CyzGetNextIrp(
  128. &Extension->CurrentMaskIrp,
  129. &Extension->MaskQueue,
  130. &NewIrp,
  131. TRUE,
  132. Extension
  133. );
  134. CyzDbgPrintEx(CYZDIAG4, "Perhaps another mask irp was found in "
  135. "the queue\n"
  136. "------- %x/%x <- values should be the same\n",
  137. Extension->CurrentMaskIrp,NewIrp);
  138. } else {
  139. //
  140. // First make sure that we have a non-zero mask.
  141. // If the app queues a wait on a zero mask it can't
  142. // be statisfied so it makes no sense to start it.
  143. //
  144. if ((!Extension->IsrWaitMask) || (Extension->CurrentWaitIrp)) {
  145. CyzDbgPrintEx(CYZDIAG4, "WaitIrp is invalid\n"
  146. "------- IsrWaitMask: %x\n"
  147. "------- CurrentWaitIrp: %x\n",
  148. Extension->IsrWaitMask,
  149. Extension->CurrentWaitIrp);
  150. Extension->CurrentMaskIrp->IoStatus.Status
  151. = STATUS_INVALID_PARAMETER;
  152. if (!SetFirstStatus) {
  153. CyzDbgPrintEx(CYZDIAG4, "%x was the first irp processed "
  154. "by this\n"
  155. "------- invocation of startmask\n",
  156. Extension->CurrentMaskIrp);
  157. FirstStatus = STATUS_INVALID_PARAMETER;
  158. SetFirstStatus = TRUE;
  159. }
  160. CyzGetNextIrp(&Extension->CurrentMaskIrp,
  161. &Extension->MaskQueue, &NewIrp, TRUE,
  162. Extension);
  163. CyzDbgPrintEx(CYZDIAG4, "Perhaps another mask irp was found "
  164. "in the queue\n"
  165. "------- %x/%x <- values should be the same\n",
  166. Extension->CurrentMaskIrp,NewIrp);
  167. } else {
  168. KIRQL OldIrql;
  169. //
  170. // Make the current mask irp the current wait irp and
  171. // get a new current mask irp. Note that when we get
  172. // the new current mask irp we DO NOT complete the
  173. // old current mask irp (which is now the current wait
  174. // irp.
  175. //
  176. // Then under the protection of the cancel spin lock
  177. // we check to see if the current wait irp needs to
  178. // be canceled
  179. //
  180. IoAcquireCancelSpinLock(&OldIrql);
  181. if (Extension->CurrentMaskIrp->Cancel) {
  182. CyzDbgPrintEx(CYZDIAG4, "%x irp was already marked as "
  183. "cancelled\n", Extension->CurrentMaskIrp);
  184. IoReleaseCancelSpinLock(OldIrql);
  185. Extension->CurrentMaskIrp->IoStatus.Status = STATUS_CANCELLED;
  186. if (!SetFirstStatus) {
  187. CyzDbgPrintEx(CYZDIAG4, "%x was the first irp "
  188. "processed by this\n"
  189. "------- invocation of startmask\n",
  190. Extension->CurrentMaskIrp);
  191. FirstStatus = STATUS_CANCELLED;
  192. SetFirstStatus = TRUE;
  193. }
  194. CyzGetNextIrp(&Extension->CurrentMaskIrp,
  195. &Extension->MaskQueue, &NewIrp, TRUE,
  196. Extension);
  197. CyzDbgPrintEx(CYZDIAG4, "Perhaps another mask irp was "
  198. "found in the queue\n"
  199. "------- %x/%x <- values should be the "
  200. "same\n", Extension->CurrentMaskIrp,
  201. NewIrp);
  202. } else {
  203. CyzDbgPrintEx(CYZDIAG4, "%x will become the current "
  204. "wait irp\n", Extension->CurrentMaskIrp);
  205. if (!SetFirstStatus) {
  206. CyzDbgPrintEx(CYZDIAG4, "%x was the first irp "
  207. "processed by this\n"
  208. "------- invocation of startmask\n",
  209. Extension->CurrentMaskIrp);
  210. FirstStatus = STATUS_PENDING;
  211. SetFirstStatus = TRUE;
  212. //
  213. // If we haven't already set a first status
  214. // then there is a chance that this packet
  215. // was never on the queue. We should mark
  216. // it as pending.
  217. //
  218. IoMarkIrpPending(Extension->CurrentMaskIrp);
  219. }
  220. //
  221. // There should never be a mask location when
  222. // there isn't a current wait irp. At this point
  223. // there shouldn't be a current wait irp also.
  224. //
  225. ASSERT(!Extension->IrpMaskLocation);
  226. ASSERT(!Extension->CurrentWaitIrp);
  227. Extension->CurrentWaitIrp = Extension->CurrentMaskIrp;
  228. SERIAL_INIT_REFERENCE(Extension->CurrentWaitIrp);
  229. IoSetCancelRoutine(
  230. Extension->CurrentWaitIrp,
  231. CyzCancelWait
  232. );
  233. //
  234. // Since the cancel routine has a reference to
  235. // the irp we need to update the reference
  236. // count.
  237. //
  238. SERIAL_SET_REFERENCE(
  239. Extension->CurrentWaitIrp,
  240. SERIAL_REF_CANCEL
  241. );
  242. #ifdef POLL
  243. KeAcquireSpinLock(&Extension->PollLock,&pollIrql);
  244. CyzGiveWaitToIsr(Extension);
  245. KeReleaseSpinLock(&Extension->PollLock,pollIrql);
  246. #else
  247. KeSynchronizeExecution(
  248. Extension->Interrupt,
  249. CyzGiveWaitToIsr,
  250. Extension
  251. );
  252. #endif
  253. // Code removed because it was causing blue-screen in the Modem Share
  254. // test case 77. When CurrentMaskIrp is set to NULL, we remove the
  255. // protection that avoid Starter to be called in CyzStartOrQueue.
  256. // We will let CyzGetNextIrp null out that pointer. Fanny.
  257. //
  258. // //
  259. // // Since it isn't really the mask irp anymore,
  260. // // null out that pointer.
  261. // //
  262. //
  263. // Extension->CurrentMaskIrp = NULL;
  264. Extension->CurrentMaskIrp = NULL; // back in Windows 2000. Fanny
  265. //
  266. // This will release the cancel spinlock for us
  267. //
  268. CyzGetNextIrpLocked(&Extension->CurrentMaskIrp,
  269. &Extension->MaskQueue, &NewIrp,
  270. FALSE, Extension, OldIrql);
  271. CyzDbgPrintEx(CYZDIAG4, "Perhaps another mask irp was "
  272. "found in the queue\n"
  273. "------- %x/%x <- values should be the "
  274. "same\n", Extension->CurrentMaskIrp,
  275. NewIrp);
  276. }
  277. }
  278. }
  279. } while (NewIrp);
  280. return FirstStatus;
  281. }
  282. BOOLEAN
  283. CyzGrabWaitFromIsr(
  284. IN PVOID Context
  285. )
  286. /*++
  287. Routine Description:
  288. This routine will check to see if the ISR still knows about
  289. a wait irp by checking to see if the IrpMaskLocation is non-null.
  290. If it is then it will zero the Irpmasklocation (which in effect
  291. grabs the irp away from the isr). This routine is only called
  292. buy the cancel code for the wait.
  293. NOTE: This is called by KeSynchronizeExecution.
  294. Arguments:
  295. Context - A pointer to the device extension
  296. Return Value:
  297. Always FALSE.
  298. --*/
  299. {
  300. PCYZ_DEVICE_EXTENSION Extension = Context;
  301. CYZ_LOCKED_PAGED_CODE();
  302. CyzDbgPrintEx(CYZDIAG3, "In CyzGrabWaitFromIsr\n");
  303. if (Extension->IrpMaskLocation) {
  304. CyzDbgPrintEx(CYZDIAG4, "The isr still owns the irp %x, mask "
  305. "location is %x\n"
  306. "------- and system buffer is %x\n",
  307. Extension->CurrentWaitIrp,Extension->IrpMaskLocation,
  308. Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer);
  309. //
  310. // The isr still "owns" the irp.
  311. //
  312. *Extension->IrpMaskLocation = 0;
  313. Extension->IrpMaskLocation = NULL;
  314. Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
  315. //
  316. // Since the isr no longer references the irp we need to
  317. // decrement the reference count.
  318. //
  319. SERIAL_CLEAR_REFERENCE(
  320. Extension->CurrentWaitIrp,
  321. SERIAL_REF_ISR
  322. );
  323. }
  324. return FALSE;
  325. }
  326. BOOLEAN
  327. CyzGiveWaitToIsr(
  328. IN PVOID Context
  329. )
  330. /*++
  331. Routine Description:
  332. This routine simply sets a variable in the device extension
  333. so that the isr knows that we have a wait irp.
  334. NOTE: This is called by KeSynchronizeExecution.
  335. NOTE: This routine assumes that it is called with the
  336. cancel spinlock held.
  337. Arguments:
  338. Context - Simply a pointer to the device extension.
  339. Return Value:
  340. Always FALSE.
  341. --*/
  342. {
  343. PCYZ_DEVICE_EXTENSION Extension = Context;
  344. CYZ_LOCKED_PAGED_CODE();
  345. CyzDbgPrintEx(CYZDIAG3, "In CyzGiveWaitToIsr\n");
  346. //
  347. // There certainly shouldn't be a current mask location at
  348. // this point since we have a new current wait irp.
  349. //
  350. ASSERT(!Extension->IrpMaskLocation);
  351. //
  352. // The isr may or may not actually reference this irp. It
  353. // won't if the wait can be satisfied immediately. However,
  354. // since it will then go through the normal completion sequence,
  355. // we need to have an incremented reference count anyway.
  356. //
  357. SERIAL_SET_REFERENCE(
  358. Extension->CurrentWaitIrp,
  359. SERIAL_REF_ISR
  360. );
  361. if (!Extension->HistoryMask) {
  362. CyzDbgPrintEx(CYZDIAG4, "No events occured prior to the wait call"
  363. "\n");
  364. //
  365. // Although this wait might not be for empty transmit
  366. // queue, it doesn't hurt anything to set it to false.
  367. //
  368. Extension->EmptiedTransmit = FALSE;
  369. //
  370. // Record where the "completion mask" should be set.
  371. //
  372. Extension->IrpMaskLocation =
  373. Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer;
  374. CyzDbgPrintEx( CYZDIAG4, "The isr owns the irp %x, mask location is "
  375. "%x\n"
  376. "------- and system buffer is %x\n",
  377. Extension->CurrentWaitIrp,Extension->IrpMaskLocation,
  378. Extension->CurrentWaitIrp->AssociatedIrp
  379. .SystemBuffer);
  380. } else {
  381. CyzDbgPrintEx(CYZDIAG4, "%x occurred prior to the wait - starting "
  382. "the\n"
  383. "------- completion code for %x\n",
  384. Extension->HistoryMask,Extension->CurrentWaitIrp);
  385. *((ULONG *)Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer) =
  386. Extension->HistoryMask;
  387. Extension->HistoryMask = 0;
  388. Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
  389. Extension->CurrentWaitIrp->IoStatus.Status = STATUS_SUCCESS;
  390. CyzInsertQueueDpc(&Extension->CommWaitDpc, NULL, NULL, Extension);
  391. }
  392. return FALSE;
  393. }
  394. BOOLEAN
  395. CyzFinishOldWait(
  396. IN PVOID Context
  397. )
  398. /*++
  399. Routine Description:
  400. This routine will check to see if the ISR still knows about
  401. a wait irp by checking to see if the Irpmasklocation is non-null.
  402. If it is then it will zero the Irpmasklocation (which in effect
  403. grabs the irp away from the isr). This routine is only called
  404. buy the cancel code for the wait.
  405. NOTE: This is called by KeSynchronizeExecution.
  406. Arguments:
  407. Context - A pointer to the device extension
  408. Return Value:
  409. Always FALSE.
  410. --*/
  411. {
  412. PCYZ_DEVICE_EXTENSION Extension = Context;
  413. CYZ_LOCKED_PAGED_CODE();
  414. CyzDbgPrintEx(CYZDIAG3, "In CyzFinishOldWait\n");
  415. if (Extension->IrpMaskLocation) {
  416. CyzDbgPrintEx(CYZDIAG4, "The isr still owns the irp %x, mask "
  417. "location is %x\n"
  418. "------- and system buffer is %x\n",
  419. Extension->CurrentWaitIrp,Extension->IrpMaskLocation,
  420. Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer);
  421. //
  422. // The isr still "owns" the irp.
  423. //
  424. *Extension->IrpMaskLocation = 0;
  425. Extension->IrpMaskLocation = NULL;
  426. Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
  427. //
  428. // We don't decrement the reference since the completion routine
  429. // will do that.
  430. //
  431. CyzInsertQueueDpc(&Extension->CommWaitDpc, NULL, NULL, Extension);
  432. }
  433. //
  434. // Don't wipe out any historical data we are still interested in.
  435. //
  436. Extension->HistoryMask &= *((ULONG *)Extension->CurrentMaskIrp->
  437. AssociatedIrp.SystemBuffer);
  438. Extension->IsrWaitMask = *((ULONG *)Extension->CurrentMaskIrp->
  439. AssociatedIrp.SystemBuffer);
  440. CyzDbgPrintEx( CYZDIAG4, "Set mask location of %x, in irp %x, with "
  441. "system buffer of %x\n",
  442. Extension->IrpMaskLocation, Extension->CurrentMaskIrp,
  443. Extension->CurrentMaskIrp->AssociatedIrp.SystemBuffer);
  444. return FALSE;
  445. }
  446. VOID
  447. CyzCancelWait(
  448. IN PDEVICE_OBJECT DeviceObject,
  449. IN PIRP Irp
  450. )
  451. /*++
  452. Routine Description:
  453. This routine is used to cancel a irp that is waiting on
  454. a comm event.
  455. Arguments:
  456. DeviceObject - Pointer to the device object for this device
  457. Irp - Pointer to the IRP for the current request
  458. Return Value:
  459. None.
  460. --*/
  461. {
  462. PCYZ_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
  463. CYZ_LOCKED_PAGED_CODE();
  464. CyzDbgPrintEx(CYZDIAG3, "In CyzCancelWait\n");
  465. CyzDbgPrintEx(CYZDIAG4, "Canceling wait for irp %x\n",
  466. Extension->CurrentWaitIrp);
  467. CyzTryToCompleteCurrent(Extension, CyzGrabWaitFromIsr,
  468. Irp->CancelIrql, STATUS_CANCELLED,
  469. &Extension->CurrentWaitIrp, NULL, NULL, NULL,
  470. NULL, NULL, SERIAL_REF_CANCEL);
  471. }
  472. VOID
  473. CyzCompleteWait(
  474. IN PKDPC Dpc,
  475. IN PVOID DeferredContext,
  476. IN PVOID SystemContext1,
  477. IN PVOID SystemContext2
  478. )
  479. {
  480. PCYZ_DEVICE_EXTENSION Extension = DeferredContext;
  481. KIRQL OldIrql;
  482. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzCompleteWait(%X)\n",
  483. Extension);
  484. CyzDbgPrintEx(CYZDIAG3, "In CyzCompleteWait\n");
  485. UNREFERENCED_PARAMETER(SystemContext1);
  486. UNREFERENCED_PARAMETER(SystemContext2);
  487. IoAcquireCancelSpinLock(&OldIrql);
  488. CyzDbgPrintEx(CYZDIAG4, "Completing wait for irp %x\n",
  489. Extension->CurrentWaitIrp);
  490. CyzTryToCompleteCurrent(Extension, NULL, OldIrql, STATUS_SUCCESS,
  491. &Extension->CurrentWaitIrp, NULL, NULL, NULL,
  492. NULL, NULL, SERIAL_REF_ISR);
  493. CyzDpcEpilogue(Extension, Dpc);
  494. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzCompleteWait\n");
  495. }
  496.