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.

1001 lines
25 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. sSDevCtr.c
  5. Abstract:
  6. This file contains dispatch routines
  7. for create and close. This file also
  8. contains routines to selectively suspend
  9. the device. The selective suspend feature
  10. is usb specific and not hardware specific.
  11. Environment:
  12. Kernel mode
  13. Notes:
  14. Copyright (c) 2000 Microsoft Corporation.
  15. All Rights Reserved.
  16. --*/
  17. #include "selSusp.h"
  18. #include "sSPnP.h"
  19. #include "sSPwr.h"
  20. #include "sSDevCtr.h"
  21. #include "sSUsr.h"
  22. #include "sSWmi.h"
  23. NTSTATUS
  24. SS_DispatchCreate(
  25. IN PDEVICE_OBJECT DeviceObject,
  26. IN PIRP Irp
  27. )
  28. /*++
  29. Routine Description:
  30. Dispatch routine for create.
  31. Arguments:
  32. DeviceObject - pointer to device object
  33. Irp - I/O request packet.
  34. Return Value:
  35. NT status value
  36. --*/
  37. {
  38. NTSTATUS ntStatus;
  39. PDEVICE_EXTENSION deviceExtension;
  40. PIO_STACK_LOCATION irpStack;
  41. PAGED_CODE();
  42. SSDbgPrint(3, ("SS_DispatchCreate - begins\n"));
  43. //
  44. // initialize variables
  45. //
  46. deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  47. irpStack = IoGetCurrentIrpStackLocation(Irp);
  48. //
  49. // set ntStatus to STATUS_SUCCESS
  50. //
  51. ntStatus = STATUS_SUCCESS;
  52. //
  53. // increment OpenHandleCounts
  54. //
  55. InterlockedIncrement(&deviceExtension->OpenHandleCount);
  56. Irp->IoStatus.Status = ntStatus;
  57. Irp->IoStatus.Information = 0;
  58. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  59. //
  60. // the device is idle if it has no open handles or pending PnP Irps
  61. // since this is create request, cancel idle req. if any
  62. //
  63. if(deviceExtension->SSEnable) {
  64. CancelSelectSuspend(deviceExtension);
  65. }
  66. SSDbgPrint(3, ("SS_DispatchCreate - ends\n"));
  67. return ntStatus;
  68. }
  69. NTSTATUS
  70. SS_DispatchClose(
  71. IN PDEVICE_OBJECT DeviceObject,
  72. IN PIRP Irp
  73. )
  74. /*++
  75. Routine Description:
  76. Dispatch routine for close.
  77. Arguments:
  78. DeviceObject - pointer to device object
  79. Irp - I/O request packet
  80. Return Value:
  81. NT status value
  82. --*/
  83. {
  84. NTSTATUS ntStatus;
  85. PDEVICE_EXTENSION deviceExtension;
  86. PIO_STACK_LOCATION irpStack;
  87. PAGED_CODE();
  88. SSDbgPrint(3, ("SS_DispatchClose - begins\n"));
  89. //
  90. // initialize variables
  91. //
  92. deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  93. irpStack = IoGetCurrentIrpStackLocation(Irp);
  94. //
  95. // set ntStatus to STATUS_SUCCESS
  96. //
  97. ntStatus = STATUS_SUCCESS;
  98. Irp->IoStatus.Status = ntStatus;
  99. Irp->IoStatus.Information = 0;
  100. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  101. InterlockedDecrement(&deviceExtension->OpenHandleCount);
  102. SSDbgPrint(3, ("SS_DispatchClose - ends\n"));
  103. return ntStatus;
  104. }
  105. NTSTATUS
  106. SS_DispatchDevCtrl(
  107. IN PDEVICE_OBJECT DeviceObject,
  108. IN PIRP Irp
  109. )
  110. /*++
  111. Routine Description:
  112. Dispatch routine for IRP_MJ_DEVICE_CONTROL
  113. Arguments:
  114. DeviceObject - pointer to device object
  115. Irp - I/O request packet
  116. Return Value:
  117. NT status value
  118. --*/
  119. {
  120. ULONG code;
  121. PVOID ioBuffer;
  122. ULONG inputBufferLength;
  123. ULONG outputBufferLength;
  124. ULONG info;
  125. NTSTATUS ntStatus;
  126. PDEVICE_EXTENSION deviceExtension;
  127. PIO_STACK_LOCATION irpStack;
  128. //
  129. // initialize variables
  130. //
  131. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  132. irpStack = IoGetCurrentIrpStackLocation(Irp);
  133. code = irpStack->Parameters.DeviceIoControl.IoControlCode;
  134. info = 0;
  135. ioBuffer = Irp->AssociatedIrp.SystemBuffer;
  136. inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  137. outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  138. SSDbgPrint(3, ("SS_DispatchDevCtrl::"));
  139. SSIoIncrement(deviceExtension);
  140. switch(code) {
  141. default :
  142. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  143. break;
  144. }
  145. Irp->IoStatus.Status = ntStatus;
  146. Irp->IoStatus.Information = info;
  147. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  148. SSDbgPrint(3, ("SS_DispatchDevCtrl::"));
  149. SSIoDecrement(deviceExtension);
  150. return ntStatus;
  151. }
  152. NTSTATUS
  153. SubmitIdleRequestIrp(
  154. IN PDEVICE_EXTENSION DeviceExtension
  155. )
  156. /*++
  157. Routine Description:
  158. This routine builds an idle request irp with an associated callback routine
  159. and a completion routine in the driver and passes the irp down the stack.
  160. Arguments:
  161. DeviceExtension - pointer to device extension
  162. Return Value:
  163. NT status value
  164. --*/
  165. {
  166. PIRP irp;
  167. NTSTATUS ntStatus;
  168. KIRQL oldIrql;
  169. PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
  170. PIO_STACK_LOCATION nextStack;
  171. //
  172. // initialize variables
  173. //
  174. irp = NULL;
  175. idleCallbackInfo = NULL;
  176. SSDbgPrint(3, ("SubmitIdleRequestIrp - begins\n"));
  177. //
  178. // if the device is not in a D0 power state,
  179. // budge out..
  180. //
  181. if(PowerDeviceD0 != DeviceExtension->DevPower) {
  182. ntStatus = STATUS_POWER_STATE_INVALID;
  183. goto SubmitIdleRequestIrp_Exit;
  184. }
  185. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  186. KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
  187. if(InterlockedExchange(&DeviceExtension->IdleReqPend, 1)) {
  188. SSDbgPrint(1, ("Idle request pending..\n"));
  189. KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
  190. ntStatus = STATUS_DEVICE_BUSY;
  191. goto SubmitIdleRequestIrp_Exit;
  192. }
  193. //
  194. // clear the NoIdleReqPendEvent because we are about
  195. // to submit an idle request. Since we are so early
  196. // to clear this event, make sure that if we fail this
  197. // request we set back the event.
  198. //
  199. KeClearEvent(&DeviceExtension->NoIdleReqPendEvent);
  200. idleCallbackInfo = ExAllocatePool(NonPagedPool,
  201. sizeof(struct _USB_IDLE_CALLBACK_INFO));
  202. if(idleCallbackInfo) {
  203. idleCallbackInfo->IdleCallback = IdleNotificationCallback;
  204. idleCallbackInfo->IdleContext = (PVOID)DeviceExtension;
  205. ASSERT(DeviceExtension->IdleCallbackInfo == NULL);
  206. DeviceExtension->IdleCallbackInfo = idleCallbackInfo;
  207. //
  208. // we use IoAllocateIrp to create an irp to selectively suspend the
  209. // device. This irp lies pending with the hub driver. When appropriate
  210. // the hub driver will invoked callback, where we power down. The completion
  211. // routine is invoked when we power back.
  212. //
  213. irp = IoAllocateIrp(DeviceExtension->TopOfStackDeviceObject->StackSize,
  214. FALSE);
  215. if(irp == NULL) {
  216. SSDbgPrint(1, ("cannot build idle request irp\n"));
  217. KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
  218. IO_NO_INCREMENT,
  219. FALSE);
  220. InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
  221. KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
  222. ExFreePool(idleCallbackInfo);
  223. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  224. goto SubmitIdleRequestIrp_Exit;
  225. }
  226. nextStack = IoGetNextIrpStackLocation(irp);
  227. nextStack->MajorFunction =
  228. IRP_MJ_INTERNAL_DEVICE_CONTROL;
  229. nextStack->Parameters.DeviceIoControl.IoControlCode =
  230. IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
  231. nextStack->Parameters.DeviceIoControl.Type3InputBuffer =
  232. idleCallbackInfo;
  233. nextStack->Parameters.DeviceIoControl.InputBufferLength =
  234. sizeof(struct _USB_IDLE_CALLBACK_INFO);
  235. IoSetCompletionRoutine(irp,
  236. IdleNotificationRequestComplete,
  237. DeviceExtension,
  238. TRUE,
  239. TRUE,
  240. TRUE);
  241. DeviceExtension->PendingIdleIrp = irp;
  242. //
  243. // we initialize the count to 2.
  244. // The reason is, if the CancelSelectSuspend routine manages
  245. // to grab the irp from the device extension, then the last of the
  246. // CancelSelectSuspend routine/IdleNotificationRequestComplete routine
  247. // to execute will free this irp. We need to have this schema so that
  248. // 1. completion routine does not attempt to touch the irp freed by
  249. // CancelSelectSuspend routine.
  250. // 2. CancelSelectSuspend routine doesnt wait for ever for the completion
  251. // routine to complete!
  252. //
  253. DeviceExtension->FreeIdleIrpCount = 2;
  254. KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
  255. //
  256. // check if the device is idle.
  257. // A check here ensures that a race condition did not
  258. // completely reverse the call sequence of SubmitIdleRequestIrp
  259. // and CancelSelectiveSuspend
  260. //
  261. if(!CanDeviceSuspend(DeviceExtension) ||
  262. PowerDeviceD0 != DeviceExtension->DevPower) {
  263. //
  264. // device cannot suspend - abort.
  265. // also irps created using IoAllocateIrp
  266. // needs to be deallocated.
  267. //
  268. SSDbgPrint(1, ("Device cannot selectively suspend - abort\n"));
  269. KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
  270. DeviceExtension->IdleCallbackInfo = NULL;
  271. DeviceExtension->PendingIdleIrp = NULL;
  272. KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
  273. IO_NO_INCREMENT,
  274. FALSE);
  275. InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
  276. KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
  277. if(idleCallbackInfo) {
  278. ExFreePool(idleCallbackInfo);
  279. }
  280. //
  281. // it is still safe to touch the local variable "irp" here.
  282. // the irp has not been passed down the stack, the irp has
  283. // no cancellation routine. The worse position is that the
  284. // CancelSelectSuspend has run after we released the spin
  285. // lock above. It is still essential to free the irp.
  286. //
  287. if(irp) {
  288. IoFreeIrp(irp);
  289. }
  290. ntStatus = STATUS_UNSUCCESSFUL;
  291. goto SubmitIdleRequestIrp_Exit;
  292. }
  293. SSDbgPrint(3, ("Cancelling the timer...\n"));
  294. //
  295. // Cancel the timer so that the DPCs are no longer fired.
  296. // Thus, we are making judicious usage of our resources.
  297. // we do not need DPCs because we already have an idle irp pending.
  298. // The timers are re-initialized in the completion routine.
  299. //
  300. KeCancelTimer(&DeviceExtension->Timer);
  301. SSDbgPrint(3, ("Submit an idle request at power state PowerDeviceD%X\n",
  302. DeviceExtension->DevPower - 1))
  303. ntStatus = IoCallDriver(DeviceExtension->TopOfStackDeviceObject, irp);
  304. if(!NT_SUCCESS(ntStatus)) {
  305. SSDbgPrint(1, ("IoCallDriver failed\n"));
  306. goto SubmitIdleRequestIrp_Exit;
  307. }
  308. }
  309. else {
  310. SSDbgPrint(1, ("Memory allocation for idleCallbackInfo failed\n"));
  311. KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
  312. IO_NO_INCREMENT,
  313. FALSE);
  314. InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
  315. KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
  316. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  317. }
  318. SubmitIdleRequestIrp_Exit:
  319. SSDbgPrint(3, ("SubmitIdleRequestIrp - ends\n"));
  320. return ntStatus;
  321. }
  322. VOID
  323. IdleNotificationCallback(
  324. IN PDEVICE_EXTENSION DeviceExtension
  325. )
  326. /*++
  327. Routine Description:
  328. "A pointer to a callback function in your driver is passed down the stack with
  329. this IOCTL, and it is this callback function that is called by USBHUB when it
  330. safe for your device to power down."
  331. "When the callback in your driver is called, all you really need to do is to
  332. to first ensure that a WaitWake Irp has been submitted for your device, if
  333. remote wake is possible for your device and then request a SetD2 (or DeviceWake)"
  334. Arguments:
  335. DeviceExtension - pointer to device extension
  336. Return Value:
  337. NT status value
  338. --*/
  339. {
  340. NTSTATUS ntStatus;
  341. POWER_STATE powerState;
  342. KEVENT irpCompletionEvent;
  343. PIRP_COMPLETION_CONTEXT irpContext;
  344. SSDbgPrint(3, ("IdleNotificationCallback - begins\n"));
  345. //
  346. // Dont idle, if the device was just disconnected or being stopped
  347. // i.e. return for the following DeviceState(s)
  348. // NotStarted, Stopped, PendingStop, PendingRemove, SurpriseRemoved, Removed
  349. //
  350. if(DeviceExtension->DeviceState != Working) {
  351. return;
  352. }
  353. //
  354. // If there is not already a WW IRP pending, submit one now
  355. //
  356. if(DeviceExtension->WaitWakeEnable) {
  357. IssueWaitWake(DeviceExtension);
  358. }
  359. //
  360. // power down the device
  361. //
  362. irpContext = (PIRP_COMPLETION_CONTEXT)
  363. ExAllocatePool(NonPagedPool,
  364. sizeof(IRP_COMPLETION_CONTEXT));
  365. if(!irpContext) {
  366. SSDbgPrint(1, ("Failed to alloc memory for irpContext\n"));
  367. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  368. }
  369. else {
  370. //
  371. // increment the count. In the HoldIoRequestWorkerRoutine, the
  372. // count is decremented twice (one for the system Irp and the
  373. // other for the device Irp. An increment here compensates for
  374. // the sytem irp..The decrement corresponding to this increment
  375. // is in the completion function
  376. //
  377. SSDbgPrint(3, ("IdleNotificationCallback::"));
  378. SSIoIncrement(DeviceExtension);
  379. powerState.DeviceState = DeviceExtension->PowerDownLevel;
  380. KeInitializeEvent(&irpCompletionEvent, NotificationEvent, FALSE);
  381. irpContext->DeviceExtension = DeviceExtension;
  382. irpContext->Event = &irpCompletionEvent;
  383. ntStatus = PoRequestPowerIrp(
  384. DeviceExtension->PhysicalDeviceObject,
  385. IRP_MN_SET_POWER,
  386. powerState,
  387. (PREQUEST_POWER_COMPLETE) PoIrpCompletionFunc,
  388. irpContext,
  389. NULL);
  390. //
  391. // if PoRequestPowerIrp returns a failure, we will release memory below
  392. //
  393. if(STATUS_PENDING == ntStatus) {
  394. SSDbgPrint(3, ("IdleNotificationCallback::"
  395. "waiting for the power irp to complete\n"));
  396. KeWaitForSingleObject(&irpCompletionEvent,
  397. Executive,
  398. KernelMode,
  399. FALSE,
  400. NULL);
  401. }
  402. }
  403. if(!NT_SUCCESS(ntStatus)) {
  404. if(irpContext) {
  405. ExFreePool(irpContext);
  406. }
  407. }
  408. SSDbgPrint(3, ("IdleNotificationCallback - ends\n"));
  409. }
  410. NTSTATUS
  411. IdleNotificationRequestComplete(
  412. IN PDEVICE_OBJECT DeviceObject,
  413. IN PIRP Irp,
  414. IN PDEVICE_EXTENSION DeviceExtension
  415. )
  416. /*++
  417. Routine Description:
  418. Completion routine for idle notification irp
  419. Arguments:
  420. DeviceObject - pointer to device object
  421. Irp - I/O request packet
  422. DeviceExtension - pointer to device extension
  423. Return Value:
  424. NT status value
  425. --*/
  426. {
  427. NTSTATUS ntStatus;
  428. POWER_STATE powerState;
  429. KIRQL oldIrql;
  430. PIRP idleIrp;
  431. LARGE_INTEGER dueTime;
  432. PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
  433. SSDbgPrint(3, ("IdleNotificationRequestCompete - begins\n"));
  434. idleIrp = NULL;
  435. //
  436. // check the Irp status
  437. //
  438. ntStatus = Irp->IoStatus.Status;
  439. if(!NT_SUCCESS(ntStatus) && ntStatus != STATUS_NOT_SUPPORTED) {
  440. SSDbgPrint(1, ("Idle irp completes with error::"));
  441. switch(ntStatus) {
  442. case STATUS_INVALID_DEVICE_REQUEST:
  443. SSDbgPrint(1, ("STATUS_INVALID_DEVICE_REQUEST\n"));
  444. break;
  445. case STATUS_CANCELLED:
  446. SSDbgPrint(1, ("STATUS_CANCELLED\n"));
  447. break;
  448. case STATUS_POWER_STATE_INVALID:
  449. SSDbgPrint(1, ("STATUS_POWER_STATE_INVALID\n"));
  450. goto IdleNotificationRequestComplete_Exit;
  451. case STATUS_DEVICE_BUSY:
  452. SSDbgPrint(1, ("STATUS_DEVICE_BUSY\n"));
  453. break;
  454. default:
  455. SSDbgPrint(1, ("default: %X\n", ntStatus));
  456. break;
  457. }
  458. //
  459. // if the irp completes in error, request for a SetD0 only if not in D0
  460. //
  461. if(PowerDeviceD0 != DeviceExtension->DevPower) {
  462. SSDbgPrint(3, ("IdleNotificationRequestComplete::"));
  463. SSIoIncrement(DeviceExtension);
  464. powerState.DeviceState = PowerDeviceD0;
  465. ntStatus = PoRequestPowerIrp(
  466. DeviceExtension->PhysicalDeviceObject,
  467. IRP_MN_SET_POWER,
  468. powerState,
  469. (PREQUEST_POWER_COMPLETE) PoIrpAsyncCompletionFunc,
  470. DeviceExtension,
  471. NULL);
  472. if(!NT_SUCCESS(ntStatus)) {
  473. SSDbgPrint(1, ("PoRequestPowerIrp failed\n"));
  474. }
  475. }
  476. }
  477. IdleNotificationRequestComplete_Exit:
  478. KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
  479. idleCallbackInfo = DeviceExtension->IdleCallbackInfo;
  480. DeviceExtension->IdleCallbackInfo = NULL;
  481. idleIrp = (PIRP) InterlockedExchangePointer(
  482. &DeviceExtension->PendingIdleIrp,
  483. NULL);
  484. InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
  485. KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
  486. if(idleCallbackInfo) {
  487. ExFreePool(idleCallbackInfo);
  488. }
  489. //
  490. // since the irp was created using IoAllocateIrp,
  491. // the Irp needs to be freed using IoFreeIrp.
  492. // Also return STATUS_MORE_PROCESSING_REQUIRED so that
  493. // the kernel does not reference this in the near future.
  494. //
  495. if(idleIrp) {
  496. SSDbgPrint(3, ("the completion routine has a valid pointer to idleIrp - "
  497. "free the irp\n"));
  498. IoFreeIrp(Irp);
  499. KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
  500. IO_NO_INCREMENT,
  501. FALSE);
  502. }
  503. else {
  504. //
  505. // The CancelSelectiveSuspend routine has grabbed the Irp from the device
  506. // extension. Now the last one to decrement the FreeIdleIrpCount should
  507. // free the irp.
  508. //
  509. if(0 == InterlockedDecrement(&DeviceExtension->FreeIdleIrpCount)) {
  510. SSDbgPrint(3, ("FreeIdleIrpCount is 0 - "
  511. "free the irp\n"));
  512. IoFreeIrp(Irp);
  513. KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
  514. IO_NO_INCREMENT,
  515. FALSE);
  516. }
  517. }
  518. if(DeviceExtension->SSEnable) {
  519. SSDbgPrint(3, ("Set the timer to fire DPCs\n"));
  520. dueTime.QuadPart = -10000 * IDLE_INTERVAL; // 5000 ms
  521. SSDbgPrint(3, ("Setting the timer...\n"));
  522. KeSetTimerEx(&DeviceExtension->Timer,
  523. dueTime,
  524. IDLE_INTERVAL, // 5000 ms
  525. &DeviceExtension->DeferredProcCall);
  526. SSDbgPrint(3, ("IdleNotificationRequestCompete - ends\n"));
  527. }
  528. return STATUS_MORE_PROCESSING_REQUIRED;
  529. }
  530. VOID
  531. CancelSelectSuspend(
  532. IN PDEVICE_EXTENSION DeviceExtension
  533. )
  534. /*++
  535. Routine Description:
  536. This routine is invoked to cancel selective suspend request.
  537. Arguments:
  538. DeviceExtension - pointer to device extension
  539. Return Value:
  540. None.
  541. --*/
  542. {
  543. PIRP irp;
  544. KIRQL oldIrql;
  545. irp = NULL;
  546. SSDbgPrint(3, ("CancelSelectSuspend - begins\n"));
  547. KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
  548. if(!CanDeviceSuspend(DeviceExtension))
  549. {
  550. SSDbgPrint(3, ("Device is not idle\n"));
  551. irp = (PIRP) InterlockedExchangePointer(
  552. &DeviceExtension->PendingIdleIrp,
  553. NULL);
  554. }
  555. KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
  556. //
  557. // since we have a valid Irp ptr,
  558. // we can call IoCancelIrp on it,
  559. // without the fear of the irp
  560. // being freed underneath us.
  561. //
  562. if(irp) {
  563. //
  564. // This routine has the irp pointer.
  565. // It is safe to call IoCancelIrp because we know that
  566. // the compleiton routine will not free this irp unless...
  567. //
  568. //
  569. if(IoCancelIrp(irp)) {
  570. SSDbgPrint(3, ("IoCancelIrp returns TRUE\n"));
  571. }
  572. else {
  573. SSDbgPrint(3, ("IoCancelIrp returns FALSE\n"));
  574. }
  575. //
  576. // ....we decrement the FreeIdleIrpCount from 2 to 1.
  577. // if completion routine runs ahead of us, then this routine
  578. // decrements the FreeIdleIrpCount from 1 to 0 and hence shall
  579. // free the irp.
  580. //
  581. if(0 == InterlockedDecrement(&DeviceExtension->FreeIdleIrpCount)) {
  582. SSDbgPrint(3, ("FreeIdleIrpCount is 0 - "
  583. "free the irp\n"));
  584. IoFreeIrp(irp);
  585. KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
  586. IO_NO_INCREMENT,
  587. FALSE);
  588. }
  589. }
  590. SSDbgPrint(3, ("CancelSelectSuspend - ends\n"));
  591. return;
  592. }
  593. VOID
  594. PoIrpCompletionFunc(
  595. IN PDEVICE_OBJECT DeviceObject,
  596. IN UCHAR MinorFunction,
  597. IN POWER_STATE PowerState,
  598. IN PVOID Context,
  599. IN PIO_STATUS_BLOCK IoStatus
  600. )
  601. /*++
  602. Routine Description:
  603. Completion routine for power irp PoRequested in
  604. IdleNotificationCallback.
  605. Arguments:
  606. DeviceObject - pointer to device object
  607. MinorFunciton - minor function for the irp.
  608. PowerState - irp power state
  609. Context - context passed to the completion function
  610. IoStatus - status block.
  611. Return Value:
  612. None
  613. --*/
  614. {
  615. PIRP_COMPLETION_CONTEXT irpContext;
  616. //
  617. // initialize variables
  618. //
  619. irpContext = NULL;
  620. if(Context) {
  621. irpContext = (PIRP_COMPLETION_CONTEXT) Context;
  622. }
  623. //
  624. // all we do is set the event and decrement the count
  625. //
  626. if(irpContext) {
  627. KeSetEvent(irpContext->Event, 0, FALSE);
  628. SSDbgPrint(3, ("PoIrpCompletionFunc::"));
  629. SSIoDecrement(irpContext->DeviceExtension);
  630. ExFreePool(irpContext);
  631. }
  632. return;
  633. }
  634. VOID
  635. PoIrpAsyncCompletionFunc(
  636. IN PDEVICE_OBJECT DeviceObject,
  637. IN UCHAR MinorFunction,
  638. IN POWER_STATE PowerState,
  639. IN PVOID Context,
  640. IN PIO_STATUS_BLOCK IoStatus
  641. )
  642. /*++
  643. Routine Description:
  644. Completion routine for power irp PoRequested in IdleNotification
  645. RequestComplete routine.
  646. Arguments:
  647. DeviceObject - pointer to device object
  648. MinorFunciton - minor function for the irp.
  649. PowerState - irp power state
  650. Context - context passed to the completion function
  651. IoStatus - status block.
  652. Return Value:
  653. None
  654. --*/
  655. {
  656. PDEVICE_EXTENSION DeviceExtension;
  657. //
  658. // initialize variables
  659. //
  660. DeviceExtension = (PDEVICE_EXTENSION) Context;
  661. //
  662. // all we do is decrement the count
  663. //
  664. SSDbgPrint(3, ("PoIrpAsyncCompletionFunc::"));
  665. SSIoDecrement(DeviceExtension);
  666. return;
  667. }
  668. VOID
  669. WWIrpCompletionFunc(
  670. IN PDEVICE_OBJECT DeviceObject,
  671. IN UCHAR MinorFunction,
  672. IN POWER_STATE PowerState,
  673. IN PVOID Context,
  674. IN PIO_STATUS_BLOCK IoStatus
  675. )
  676. /*++
  677. Routine Description:
  678. Completion routine for PoRequest wait wake irp
  679. Arguments:
  680. DeviceObject - pointer to device object
  681. MinorFunciton - minor function for the irp.
  682. PowerState - irp power state
  683. Context - context passed to the completion function
  684. IoStatus - status block.
  685. Return Value:
  686. None
  687. --*/
  688. {
  689. PDEVICE_EXTENSION DeviceExtension;
  690. //
  691. // initialize variables
  692. //
  693. DeviceExtension = (PDEVICE_EXTENSION) Context;
  694. //
  695. // all we do is decrement the count
  696. //
  697. SSDbgPrint(3, ("WWIrpCompletionFunc::"));
  698. SSIoDecrement(DeviceExtension);
  699. return;
  700. }