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.

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