Source code of Windows XP (NT5)
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.

741 lines
19 KiB

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