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.

739 lines
24 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. polled.c
  5. Abstract
  6. Read handling routines
  7. Author:
  8. Ervin P.
  9. Environment:
  10. Kernel mode only
  11. Revision History:
  12. --*/
  13. #include "pch.h"
  14. /*
  15. ********************************************************************************
  16. * CompleteQueuedIrpsForPolled
  17. ********************************************************************************
  18. *
  19. * Complete all waiting client reads with the given report value.
  20. *
  21. * Note: report is a 'cooked' report (i.e. it already has the report id added).
  22. *
  23. */
  24. VOID CompleteQueuedIrpsForPolled( FDO_EXTENSION *fdoExt,
  25. ULONG collectionNum,
  26. PUCHAR report,
  27. ULONG reportLen,
  28. NTSTATUS status)
  29. {
  30. PHIDCLASS_COLLECTION hidCollection;
  31. hidCollection = GetHidclassCollection(fdoExt, collectionNum);
  32. if (hidCollection){
  33. PLIST_ENTRY listEntry;
  34. LIST_ENTRY irpsToComplete;
  35. PIRP irp;
  36. ULONG actualLen;
  37. /*
  38. * Note: In order to avoid an infinite loop with a client that
  39. * resubmits the read each in his completion routine,
  40. * we must build a separate list of IRPs to be completed
  41. * while holding the spinlock continuously.
  42. */
  43. InitializeListHead(&irpsToComplete);
  44. if (hidCollection->secureReadMode) {
  45. while (irp = DequeuePolledReadSystemIrp(hidCollection)){
  46. InsertTailList(&irpsToComplete, &irp->Tail.Overlay.ListEntry);
  47. }
  48. } else {
  49. while (irp = DequeuePolledReadIrp(hidCollection)){
  50. InsertTailList(&irpsToComplete, &irp->Tail.Overlay.ListEntry);
  51. }
  52. }
  53. while (!IsListEmpty(&irpsToComplete)){
  54. PIO_STACK_LOCATION stackPtr;
  55. PHIDCLASS_FILE_EXTENSION fileExtension;
  56. listEntry = RemoveHeadList(&irpsToComplete);
  57. irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
  58. stackPtr = IoGetCurrentIrpStackLocation(irp);
  59. ASSERT(stackPtr);
  60. fileExtension = (PHIDCLASS_FILE_EXTENSION)stackPtr->FileObject->FsContext;
  61. ASSERT(fileExtension->Signature == HIDCLASS_FILE_EXTENSION_SIG);
  62. actualLen = 0;
  63. if (NT_SUCCESS(status)){
  64. PUCHAR callerBuf;
  65. callerBuf = HidpGetSystemAddressForMdlSafe(irp->MdlAddress);
  66. if (callerBuf && (stackPtr->Parameters.Read.Length >= reportLen)){
  67. RtlCopyMemory(callerBuf, report, reportLen);
  68. irp->IoStatus.Information = actualLen = reportLen;
  69. } else {
  70. status = STATUS_INVALID_USER_BUFFER;
  71. }
  72. }
  73. DBG_RECORD_READ(irp, actualLen, (ULONG)report[0], TRUE)
  74. irp->IoStatus.Status = status;
  75. fileExtension->nowCompletingIrpForOpportunisticReader++;
  76. IoCompleteRequest(irp, IO_KEYBOARD_INCREMENT);
  77. fileExtension->nowCompletingIrpForOpportunisticReader--;
  78. }
  79. }
  80. else {
  81. TRAP;
  82. }
  83. }
  84. /*
  85. ********************************************************************************
  86. * HidpPolledReadComplete
  87. ********************************************************************************
  88. *
  89. * Note: the context passed to this callback is the PDO extension for
  90. * the collection which initiated this read; however, the returned
  91. * report may be for another collection.
  92. */
  93. NTSTATUS HidpPolledReadComplete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
  94. {
  95. PDO_EXTENSION *pdoExt = (PDO_EXTENSION *)Context;
  96. FDO_EXTENSION *fdoExt = &pdoExt->deviceFdoExt->fdoExt;
  97. PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);
  98. ULONG reportId;
  99. PHIDP_REPORT_IDS reportIdent;
  100. DBG_COMMON_ENTRY()
  101. ASSERT(pdoExt->deviceFdoExt->Signature == HID_DEVICE_EXTENSION_SIG);
  102. ASSERT(ISPTR(Irp->UserBuffer));
  103. fdoExt->outstandingRequests--;
  104. if (fdoExt->deviceDesc.ReportIDs[0].ReportID == 0) {
  105. /*
  106. * We previously incremented the UserBuffer to knock off the report id,
  107. * so restore it now and set the default report id.
  108. */
  109. *(PUCHAR)(--(PUCHAR)Irp->UserBuffer) = (UCHAR)0;
  110. if (NT_SUCCESS(Irp->IoStatus.Status)){
  111. Irp->IoStatus.Information++;
  112. }
  113. }
  114. /*
  115. * WHETHER OR NOT THE CALL SUCCEEDED,
  116. * we'll complete the waiting client read IRPs with
  117. * the result of this read.
  118. */
  119. reportId = (ULONG)(*(PUCHAR)Irp->UserBuffer);
  120. reportIdent = GetReportIdentifier(fdoExt, reportId);
  121. if (reportIdent){
  122. ULONG collectionNum = reportIdent->CollectionNumber;
  123. PHIDCLASS_COLLECTION hidpCollection = GetHidclassCollection(fdoExt, collectionNum);
  124. PHIDP_COLLECTION_DESC hidCollectionDesc = GetCollectionDesc(fdoExt, collectionNum);
  125. if (hidpCollection && hidCollectionDesc){
  126. ULONG reportLen = (ULONG)Irp->IoStatus.Information;
  127. ASSERT((reportLen == hidCollectionDesc->InputLength) || !NT_SUCCESS(Irp->IoStatus.Status));
  128. if (NT_SUCCESS(Irp->IoStatus.Status)){
  129. KIRQL oldIrql;
  130. /*
  131. * If this report contains a power-button event, alert the system.
  132. */
  133. CheckReportPowerEvent( fdoExt,
  134. hidpCollection,
  135. Irp->UserBuffer,
  136. reportLen);
  137. /*
  138. * Save this report for "opportunistic" polled device
  139. * readers who want a result right away.
  140. * Use the polledDeviceReadQueueSpinLock to protect
  141. * the savedPolledReportBuf.
  142. */
  143. if (hidpCollection->secureReadMode) {
  144. hidpCollection->polledDataIsStale = TRUE;
  145. } else {
  146. KeAcquireSpinLock(&hidpCollection->polledDeviceReadQueueSpinLock, &oldIrql);
  147. ASSERT(reportLen <= fdoExt->maxReportSize+1);
  148. RtlCopyMemory(hidpCollection->savedPolledReportBuf, Irp->UserBuffer, reportLen);
  149. hidpCollection->savedPolledReportLen = reportLen;
  150. hidpCollection->polledDataIsStale = FALSE;
  151. KeReleaseSpinLock(&hidpCollection->polledDeviceReadQueueSpinLock, oldIrql);
  152. }
  153. }
  154. /*
  155. * Copy this report for all queued read IRPs on this polled device.
  156. * Do this AFTER updating the savedPolledReport information
  157. * because many clients will issue a read again immediately
  158. * from the completion routine.
  159. */
  160. CompleteQueuedIrpsForPolled( fdoExt,
  161. collectionNum,
  162. Irp->UserBuffer,
  163. reportLen,
  164. Irp->IoStatus.Status);
  165. }
  166. else {
  167. TRAP;
  168. }
  169. }
  170. else {
  171. TRAP;
  172. }
  173. /*
  174. * This is an IRP we created to poll the device.
  175. * Free the buffer we allocated for the read.
  176. */
  177. ExFreePool(Irp->UserBuffer);
  178. IoFreeIrp(Irp);
  179. /*
  180. * MUST return STATUS_MORE_PROCESSING_REQUIRED here or
  181. * NTKERN will touch the IRP.
  182. */
  183. DBG_COMMON_EXIT()
  184. return STATUS_MORE_PROCESSING_REQUIRED;
  185. }
  186. /*
  187. ********************************************************************************
  188. * HidpPolledReadComplete_TimerDriven
  189. ********************************************************************************
  190. *
  191. */
  192. NTSTATUS HidpPolledReadComplete_TimerDriven(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
  193. {
  194. PDO_EXTENSION *pdoExt = (PDO_EXTENSION *)Context;
  195. FDO_EXTENSION *fdoExt = &pdoExt->deviceFdoExt->fdoExt;
  196. NTSTATUS status;
  197. /*
  198. * Call the actual completion routine.
  199. */
  200. status = HidpPolledReadComplete(DeviceObject, Irp, Context);
  201. /*
  202. * Reset the timer of the collection which initiated this read,
  203. * (which may be different than the collection that returned the report).
  204. */
  205. if (pdoExt->state == COLLECTION_STATE_RUNNING){
  206. PHIDCLASS_COLLECTION originatorCollection =
  207. GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  208. if (originatorCollection){
  209. LARGE_INTEGER timeout;
  210. timeout.HighPart = -1;
  211. timeout.LowPart = -(LONG)(originatorCollection->PollInterval_msec*10000);
  212. KeSetTimer( &originatorCollection->polledDeviceTimer,
  213. timeout,
  214. &originatorCollection->polledDeviceTimerDPC);
  215. }
  216. else {
  217. TRAP;
  218. }
  219. }
  220. return status;
  221. }
  222. /*
  223. * ReadPolledDevice
  224. *
  225. * Issue a read to the polled device on behalf of the
  226. * top-level collection indicated by pdoExt.
  227. * (Note that because we keep separate polling loops for
  228. * each collection, we do reads on behalf of specific collections).
  229. *
  230. */
  231. BOOLEAN ReadPolledDevice(PDO_EXTENSION *pdoExt, BOOLEAN isTimerDrivenRead)
  232. {
  233. BOOLEAN didPollDevice = FALSE;
  234. FDO_EXTENSION *fdoExt;
  235. PHIDP_COLLECTION_DESC hidCollectionDesc;
  236. fdoExt = &pdoExt->deviceFdoExt->fdoExt;
  237. hidCollectionDesc = GetCollectionDesc(fdoExt, pdoExt->collectionNum);
  238. if (hidCollectionDesc){
  239. PIRP irp = IoAllocateIrp(fdoExt->fdo->StackSize, FALSE);
  240. if (irp){
  241. /*
  242. * We cannot issue a read on a specific collection.
  243. * But we'll allocate a buffer just large enough for a report
  244. * on the collection we want.
  245. * Note that hidCollectionDesc->InputLength includes
  246. * the report id byte, which we may have to prepend ourselves.
  247. */
  248. ULONG reportLen = hidCollectionDesc->InputLength;
  249. irp->UserBuffer = ALLOCATEPOOL(NonPagedPool, reportLen);
  250. if (irp->UserBuffer){
  251. PIO_COMPLETION_ROUTINE completionRoutine;
  252. PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(irp);
  253. ASSERT(nextStack);
  254. if (fdoExt->deviceDesc.ReportIDs[0].ReportID == 0) {
  255. /*
  256. * This device has only one report type,
  257. * so the minidriver will not include the 1-byte report id
  258. * (which is implicitly zero).
  259. * However, we still need to return a 'cooked' report,
  260. * with the report id, to the user; so bump the buffer
  261. * we pass down to make room for the report id.
  262. */
  263. *(((PUCHAR)irp->UserBuffer)++) = (UCHAR)0;
  264. reportLen--;
  265. }
  266. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  267. nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_READ_REPORT;
  268. nextStack->Parameters.DeviceIoControl.OutputBufferLength = reportLen;
  269. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  270. completionRoutine = (isTimerDrivenRead) ?
  271. HidpPolledReadComplete_TimerDriven :
  272. HidpPolledReadComplete;
  273. IoSetCompletionRoutine( irp,
  274. completionRoutine,
  275. (PVOID)pdoExt, // context
  276. TRUE,
  277. TRUE,
  278. TRUE );
  279. fdoExt->outstandingRequests++;
  280. HidpCallDriver(fdoExt->fdo, irp);
  281. didPollDevice = TRUE;
  282. }
  283. }
  284. }
  285. else {
  286. ASSERT(hidCollectionDesc);
  287. }
  288. return didPollDevice;
  289. }
  290. /*
  291. ********************************************************************************
  292. * HidpPolledTimerDpc
  293. ********************************************************************************
  294. *
  295. *
  296. *
  297. */
  298. VOID HidpPolledTimerDpc( IN PKDPC Dpc,
  299. IN PVOID DeferredContext,
  300. IN PVOID SystemArgument1,
  301. IN PVOID SystemArgument2
  302. )
  303. {
  304. PDO_EXTENSION *pdoExt = (PDO_EXTENSION *)DeferredContext;
  305. FDO_EXTENSION *fdoExt = &pdoExt->deviceFdoExt->fdoExt;
  306. ASSERT(pdoExt->deviceFdoExt->Signature == HID_DEVICE_EXTENSION_SIG);
  307. if (pdoExt->state == COLLECTION_STATE_RUNNING){
  308. PHIDCLASS_COLLECTION hidCollection;
  309. hidCollection = GetHidclassCollection(fdoExt, pdoExt->collectionNum);
  310. if (hidCollection){
  311. KIRQL oldIrql;
  312. BOOLEAN haveReadIrpsQueued;
  313. BOOLEAN didPollDevice = FALSE;
  314. /*
  315. * If there are reads pending on this collection,
  316. * issue a read to the device.
  317. *
  318. * Note: we have no control over which collection we are reading.
  319. * This read may end up returning a report for a different
  320. * collection! That's ok, since a report for this collection
  321. * will eventually be returned.
  322. */
  323. KeAcquireSpinLock(&hidCollection->polledDeviceReadQueueSpinLock, &oldIrql);
  324. haveReadIrpsQueued = !IsListEmpty(&hidCollection->polledDeviceReadQueue);
  325. KeReleaseSpinLock(&hidCollection->polledDeviceReadQueueSpinLock, oldIrql);
  326. if (haveReadIrpsQueued){
  327. didPollDevice = ReadPolledDevice(pdoExt, TRUE);
  328. }
  329. else {
  330. /*
  331. * The timer period has expired, so any saved reports
  332. * are now stale.
  333. */
  334. hidCollection->polledDataIsStale = TRUE;
  335. }
  336. /*
  337. * If we actually polled the device, we'll reset the timer in the
  338. * completion routine; otherwise, we do it here.
  339. */
  340. if (!didPollDevice){
  341. LARGE_INTEGER timeout;
  342. timeout.HighPart = -1;
  343. timeout.LowPart = -(LONG)(hidCollection->PollInterval_msec*10000);
  344. KeSetTimer( &hidCollection->polledDeviceTimer,
  345. timeout,
  346. &hidCollection->polledDeviceTimerDPC);
  347. }
  348. }
  349. else {
  350. TRAP;
  351. }
  352. }
  353. }
  354. /*
  355. ********************************************************************************
  356. * StartPollingLoop
  357. ********************************************************************************
  358. *
  359. * Start a polling loop for a particular collection.
  360. *
  361. */
  362. BOOLEAN StartPollingLoop( FDO_EXTENSION *fdoExt,
  363. PHIDCLASS_COLLECTION hidCollection,
  364. BOOLEAN freshQueue)
  365. {
  366. ULONG ctnIndex = hidCollection->CollectionIndex;
  367. LARGE_INTEGER timeout;
  368. KIRQL oldIrql;
  369. if (freshQueue){
  370. InitializeListHead(&hidCollection->polledDeviceReadQueue);
  371. KeInitializeSpinLock(&hidCollection->polledDeviceReadQueueSpinLock);
  372. KeInitializeTimer(&hidCollection->polledDeviceTimer);
  373. }
  374. /*
  375. * Use polledDeviceReadQueueSpinLock to protect the timer structures as well
  376. * as the queue.
  377. */
  378. KeAcquireSpinLock(&hidCollection->polledDeviceReadQueueSpinLock, &oldIrql);
  379. KeInitializeDpc( &hidCollection->polledDeviceTimerDPC,
  380. HidpPolledTimerDpc,
  381. &fdoExt->collectionPdoExtensions[ctnIndex]->pdoExt);
  382. KeReleaseSpinLock(&hidCollection->polledDeviceReadQueueSpinLock, oldIrql);
  383. timeout.HighPart = -1;
  384. timeout.LowPart = -(LONG)(hidCollection->PollInterval_msec*10000);
  385. KeSetTimer( &hidCollection->polledDeviceTimer,
  386. timeout,
  387. &hidCollection->polledDeviceTimerDPC);
  388. return TRUE;
  389. }
  390. /*
  391. ********************************************************************************
  392. * StopPollingLoop
  393. ********************************************************************************
  394. *
  395. *
  396. *
  397. */
  398. VOID StopPollingLoop(PHIDCLASS_COLLECTION hidCollection, BOOLEAN flushQueue)
  399. {
  400. KIRQL oldIrql;
  401. /*
  402. * Use polledDeviceReadQueueSpinLock to protect the timer structures as well
  403. * as the queue.
  404. */
  405. KeAcquireSpinLock(&hidCollection->polledDeviceReadQueueSpinLock, &oldIrql);
  406. KeCancelTimer(&hidCollection->polledDeviceTimer);
  407. KeInitializeTimer(&hidCollection->polledDeviceTimer);
  408. KeReleaseSpinLock(&hidCollection->polledDeviceReadQueueSpinLock, oldIrql);
  409. /*
  410. * Fail all the queued IRPs.
  411. */
  412. if (flushQueue){
  413. PIRP irp;
  414. LIST_ENTRY irpsToComplete;
  415. /*
  416. * Move the IRPs to a temporary queue first so they don't get requeued
  417. * on the completion thread and cause us to loop forever.
  418. */
  419. InitializeListHead(&irpsToComplete);
  420. while (irp = DequeuePolledReadIrp(hidCollection)){
  421. InsertTailList(&irpsToComplete, &irp->Tail.Overlay.ListEntry);
  422. }
  423. while (!IsListEmpty(&irpsToComplete)){
  424. PLIST_ENTRY listEntry = RemoveHeadList(&irpsToComplete);
  425. irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
  426. DBG_RECORD_READ(irp, 0, 0, TRUE)
  427. irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
  428. irp->IoStatus.Information = 0;
  429. IoCompleteRequest(irp, IO_NO_INCREMENT);
  430. }
  431. }
  432. }
  433. /*
  434. ********************************************************************************
  435. * PolledReadCancelRoutine
  436. ********************************************************************************
  437. *
  438. * We need to set an IRP's cancel routine to non-NULL before
  439. * we queue it; so just use a pointer this NULL function.
  440. *
  441. */
  442. VOID PolledReadCancelRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  443. {
  444. PHIDCLASS_DEVICE_EXTENSION hidDeviceExtension = (PHIDCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
  445. FDO_EXTENSION *fdoExt;
  446. PHIDCLASS_COLLECTION hidCollection;
  447. ULONG collectionIndex;
  448. KIRQL oldIrql;
  449. IoReleaseCancelSpinLock(Irp->CancelIrql);
  450. ASSERT(hidDeviceExtension->Signature == HID_DEVICE_EXTENSION_SIG);
  451. ASSERT(hidDeviceExtension->isClientPdo);
  452. fdoExt = &hidDeviceExtension->pdoExt.deviceFdoExt->fdoExt;
  453. collectionIndex = hidDeviceExtension->pdoExt.collectionIndex;
  454. hidCollection = &fdoExt->classCollectionArray[collectionIndex];
  455. KeAcquireSpinLock(&hidCollection->polledDeviceReadQueueSpinLock, &oldIrql);
  456. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  457. ASSERT(hidCollection->numPendingReads > 0);
  458. hidCollection->numPendingReads--;
  459. KeReleaseSpinLock(&hidCollection->polledDeviceReadQueueSpinLock, oldIrql);
  460. Irp->IoStatus.Status = STATUS_CANCELLED;
  461. DBG_RECORD_READ(Irp, 0, 0, TRUE)
  462. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  463. }
  464. NTSTATUS EnqueuePolledReadIrp(PHIDCLASS_COLLECTION collection, PIRP Irp)
  465. {
  466. NTSTATUS status;
  467. KIRQL oldIrql;
  468. PDRIVER_CANCEL oldCancelRoutine;
  469. KeAcquireSpinLock(&collection->polledDeviceReadQueueSpinLock, &oldIrql);
  470. /*
  471. * Must set a cancel routine before
  472. * checking the Cancel flag.
  473. */
  474. oldCancelRoutine = IoSetCancelRoutine(Irp, PolledReadCancelRoutine);
  475. ASSERT(!oldCancelRoutine);
  476. /*
  477. * Make sure this Irp wasn't just cancelled.
  478. * Note that there is NO RACE CONDITION here
  479. * because we are holding the fileExtension lock.
  480. */
  481. if (Irp->Cancel){
  482. /*
  483. * This IRP was cancelled.
  484. */
  485. oldCancelRoutine = IoSetCancelRoutine(Irp, NULL);
  486. if (oldCancelRoutine){
  487. /*
  488. * The cancel routine was NOT called.
  489. * Return error so that caller completes the IRP.
  490. */
  491. DBG_RECORD_READ(Irp, IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length, 0, TRUE)
  492. ASSERT(oldCancelRoutine == PolledReadCancelRoutine);
  493. status = STATUS_CANCELLED;
  494. }
  495. else {
  496. /*
  497. * The cancel routine was called.
  498. * As soon as we drop the spinlock it will dequeue
  499. * and complete the IRP.
  500. * Initialize the IRP's listEntry so that the dequeue
  501. * doesn't cause corruption.
  502. * Then don't touch the irp.
  503. */
  504. InitializeListHead(&Irp->Tail.Overlay.ListEntry);
  505. collection->numPendingReads++; // because cancel routine will decrement
  506. IoMarkIrpPending(Irp);
  507. status = Irp->IoStatus.Status = STATUS_PENDING;
  508. }
  509. }
  510. else {
  511. DBG_RECORD_READ(Irp, IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length, 0, FALSE)
  512. /*
  513. * There are no reports waiting.
  514. * Queue this irp onto the file extension's list of pending irps.
  515. */
  516. InsertTailList(&collection->polledDeviceReadQueue, &Irp->Tail.Overlay.ListEntry);
  517. collection->numPendingReads++;
  518. IoMarkIrpPending(Irp);
  519. status = Irp->IoStatus.Status = STATUS_PENDING;
  520. }
  521. KeReleaseSpinLock(&collection->polledDeviceReadQueueSpinLock, oldIrql);
  522. DBGSUCCESS(status, TRUE)
  523. return status;
  524. }
  525. PIRP DequeuePolledReadSystemIrp(PHIDCLASS_COLLECTION collection)
  526. {
  527. KIRQL oldIrql;
  528. PIRP irp = NULL;
  529. PLIST_ENTRY listEntry;
  530. PHIDCLASS_FILE_EXTENSION fileExtension;
  531. PFILE_OBJECT fileObject;
  532. PIO_STACK_LOCATION irpSp;
  533. KeAcquireSpinLock(&collection->polledDeviceReadQueueSpinLock, &oldIrql);
  534. listEntry = &collection->polledDeviceReadQueue;
  535. while (!irp && ((listEntry = listEntry->Flink) != &collection->polledDeviceReadQueue)) {
  536. PDRIVER_CANCEL oldCancelRoutine;
  537. irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
  538. irpSp = IoGetCurrentIrpStackLocation(irp);
  539. fileObject = irpSp->FileObject;
  540. fileExtension = (PHIDCLASS_FILE_EXTENSION)fileObject->FsContext;
  541. if (!fileExtension->isSecureOpen) {
  542. irp = NULL;
  543. continue;
  544. }
  545. RemoveEntryList(listEntry);
  546. oldCancelRoutine = IoSetCancelRoutine(irp, NULL);
  547. if (oldCancelRoutine){
  548. ASSERT(oldCancelRoutine == PolledReadCancelRoutine);
  549. ASSERT(collection->numPendingReads > 0);
  550. collection->numPendingReads--;
  551. }
  552. else {
  553. /*
  554. * IRP was cancelled and cancel routine was called.
  555. * As soon as we drop the spinlock,
  556. * the cancel routine will dequeue and complete this IRP.
  557. * Initialize the IRP's listEntry so that the dequeue doesn't cause corruption.
  558. * Then, don't touch the IRP.
  559. */
  560. ASSERT(irp->Cancel);
  561. InitializeListHead(&irp->Tail.Overlay.ListEntry);
  562. irp = NULL;
  563. }
  564. }
  565. KeReleaseSpinLock(&collection->polledDeviceReadQueueSpinLock, oldIrql);
  566. return irp;
  567. }
  568. PIRP DequeuePolledReadIrp(PHIDCLASS_COLLECTION collection)
  569. {
  570. KIRQL oldIrql;
  571. PIRP irp = NULL;
  572. KeAcquireSpinLock(&collection->polledDeviceReadQueueSpinLock, &oldIrql);
  573. while (!irp && !IsListEmpty(&collection->polledDeviceReadQueue)){
  574. PDRIVER_CANCEL oldCancelRoutine;
  575. PLIST_ENTRY listEntry = RemoveHeadList(&collection->polledDeviceReadQueue);
  576. irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
  577. oldCancelRoutine = IoSetCancelRoutine(irp, NULL);
  578. if (oldCancelRoutine){
  579. ASSERT(oldCancelRoutine == PolledReadCancelRoutine);
  580. ASSERT(collection->numPendingReads > 0);
  581. collection->numPendingReads--;
  582. }
  583. else {
  584. /*
  585. * IRP was cancelled and cancel routine was called.
  586. * As soon as we drop the spinlock,
  587. * the cancel routine will dequeue and complete this IRP.
  588. * Initialize the IRP's listEntry so that the dequeue doesn't cause corruption.
  589. * Then, don't touch the IRP.
  590. */
  591. ASSERT(irp->Cancel);
  592. InitializeListHead(&irp->Tail.Overlay.ListEntry);
  593. irp = NULL;
  594. }
  595. }
  596. KeReleaseSpinLock(&collection->polledDeviceReadQueueSpinLock, oldIrql);
  597. return irp;
  598. }