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.

1667 lines
39 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. sSPwr.c
  5. Abstract:
  6. The power management related processing.
  7. The Power Manager uses IRPs to direct drivers to change system
  8. and device power levels, to respond to system wake-up events,
  9. and to query drivers about their devices. All power IRPs have
  10. the major function code IRP_MJ_POWER.
  11. Most function and filter drivers perform some processing for
  12. each power IRP, then pass the IRP down to the next lower driver
  13. without completing it. Eventually the IRP reaches the bus driver,
  14. which physically changes the power state of the device and completes
  15. the IRP.
  16. When the IRP has been completed, the I/O Manager calls any
  17. IoCompletion routines set by drivers as the IRP traveled
  18. down the device stack. Whether a driver needs to set a completion
  19. routine depends upon the type of IRP and the driver's individual
  20. requirements.
  21. This code is not USB specific. It is essential for every WDM driver
  22. to handle power irps.
  23. Environment:
  24. Kernel mode
  25. Notes:
  26. Copyright (c) 2000 Microsoft Corporation.
  27. All Rights Reserved.
  28. --*/
  29. #include "selSusp.h"
  30. #include "sSPwr.h"
  31. #include "sSPnP.h"
  32. #include "sSDevCtr.h"
  33. #include "sSUsr.h"
  34. #include "sSWmi.h"
  35. NTSTATUS
  36. SS_DispatchPower(
  37. IN PDEVICE_OBJECT DeviceObject,
  38. IN PIRP Irp
  39. )
  40. /*++
  41. Routine Description:
  42. The power dispatch routine.
  43. Arguments:
  44. DeviceObject - pointer to a device object.
  45. Irp - pointer to an I/O Request Packet.
  46. Return Value:
  47. NT status code
  48. --*/
  49. {
  50. NTSTATUS ntStatus;
  51. PIO_STACK_LOCATION irpStack;
  52. PUNICODE_STRING tagString;
  53. PDEVICE_EXTENSION deviceExtension;
  54. //
  55. // initialize the variables
  56. //
  57. irpStack = IoGetCurrentIrpStackLocation(Irp);
  58. deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  59. //
  60. // We don't queue power Irps, we'll only check if the
  61. // device was removed, otherwise we'll take appropriate
  62. // action and send it to the next lower driver. In general
  63. // drivers should not cause long delays while handling power
  64. // IRPs. If a driver cannot handle a power IRP in a brief time,
  65. // it should return STATUS_PENDING and queue all incoming
  66. // IRPs until the IRP completes.
  67. //
  68. if(Removed == deviceExtension->DeviceState) {
  69. //
  70. // Even if a driver fails the IRP, it must nevertheless call
  71. // PoStartNextPowerIrp to inform the Power Manager that it
  72. // is ready to handle another power IRP.
  73. //
  74. PoStartNextPowerIrp(Irp);
  75. Irp->IoStatus.Status = ntStatus = STATUS_DELETE_PENDING;
  76. Irp->IoStatus.Information = 0;
  77. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  78. return ntStatus;
  79. }
  80. if(NotStarted == deviceExtension->DeviceState) {
  81. //
  82. // if the device is not started yet, pass it down
  83. //
  84. PoStartNextPowerIrp(Irp);
  85. IoSkipCurrentIrpStackLocation(Irp);
  86. return PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  87. }
  88. SSDbgPrint(3, ("SS_DispatchPower::"));
  89. SSIoIncrement(deviceExtension);
  90. switch(irpStack->MinorFunction) {
  91. case IRP_MN_SET_POWER:
  92. //
  93. // The Power Manager sends this IRP for one of the
  94. // following reasons:
  95. // 1) To notify drivers of a change to the system power state.
  96. // 2) To change the power state of a device for which
  97. // the Power Manager is performing idle detection.
  98. // A driver sends IRP_MN_SET_POWER to change the power
  99. // state of its device if it's a power policy owner for the
  100. // device.
  101. //
  102. //
  103. // Mark the Irp as pending and return STATUS_PENDING if we change the
  104. // nature of the irp in the completion routine (asynchroniticity).
  105. // In such cases, do not return the status returned by the lower driver.
  106. // returning STATUS_MORE_PROCESSING_REQUIRED in the completion routine
  107. // transforms the nature of the irp to asynchronous irp.
  108. //
  109. IoMarkIrpPending(Irp);
  110. switch(irpStack->Parameters.Power.Type) {
  111. case SystemPowerState:
  112. HandleSystemSetPower(DeviceObject, Irp);
  113. ntStatus = STATUS_PENDING;
  114. break;
  115. case DevicePowerState:
  116. HandleDeviceSetPower(DeviceObject, Irp);
  117. ntStatus = STATUS_PENDING;
  118. break;
  119. }
  120. break;
  121. case IRP_MN_QUERY_POWER:
  122. //
  123. // The Power Manager sends a power IRP with the minor
  124. // IRP code IRP_MN_QUERY_POWER to determine whether it
  125. // can safely change to the specified system power state
  126. // (S1-S5) and to allow drivers to prepare for such a change.
  127. // If a driver can put its device in the requested state,
  128. // it sets status to STATUS_SUCCESS and passes the IRP down.
  129. //
  130. IoMarkIrpPending(Irp);
  131. switch(irpStack->Parameters.Power.Type) {
  132. case SystemPowerState:
  133. HandleSystemQueryPower(DeviceObject, Irp);
  134. ntStatus = STATUS_PENDING;
  135. break;
  136. case DevicePowerState:
  137. HandleDeviceQueryPower(DeviceObject, Irp);
  138. ntStatus = STATUS_PENDING;
  139. break;
  140. }
  141. break;
  142. case IRP_MN_WAIT_WAKE:
  143. //
  144. // The minor power IRP code IRP_MN_WAIT_WAKE provides
  145. // for waking a device or waking the system. Drivers
  146. // of devices that can wake themselves or the system
  147. // send IRP_MN_WAIT_WAKE. The system sends IRP_MN_WAIT_WAKE
  148. // only to devices that always wake the system, such as
  149. // the power-on switch.
  150. //
  151. IoMarkIrpPending(Irp);
  152. IoCopyCurrentIrpStackLocationToNext(Irp);
  153. IoSetCompletionRoutine(
  154. Irp,
  155. (PIO_COMPLETION_ROUTINE)WaitWakeCompletionRoutine,
  156. deviceExtension,
  157. TRUE,
  158. TRUE,
  159. TRUE);
  160. PoStartNextPowerIrp(Irp);
  161. ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  162. if(!NT_SUCCESS(ntStatus)) {
  163. SSDbgPrint(1, ("Lower drivers failed the IRP_MN_WAIT_WAKE Irp\n"));
  164. }
  165. //
  166. // since we marked the Irp as pending; we should return STATUS_PENDING
  167. //
  168. ntStatus = STATUS_PENDING;
  169. //
  170. // push back the count HERE and NOT in completion routine
  171. // a pending Wait Wake Irp should not impede stopping the device
  172. //
  173. SSDbgPrint(3, ("IRP_MN_WAIT_WAKE::"));
  174. SSIoDecrement(deviceExtension);
  175. break;
  176. case IRP_MN_POWER_SEQUENCE:
  177. //
  178. // A driver sends this IRP as an optimization to determine
  179. // whether its device actually entered a specific power state.
  180. // This IRP is optional. Power Manager cannot send this IRP.
  181. //
  182. default:
  183. PoStartNextPowerIrp(Irp);
  184. IoSkipCurrentIrpStackLocation(Irp);
  185. ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  186. if(!NT_SUCCESS(ntStatus)) {
  187. SSDbgPrint(1, ("Lower drivers failed default power Irp\n"));
  188. }
  189. SSDbgPrint(3, ("SS_DispatchPower::"));
  190. SSIoDecrement(deviceExtension);
  191. break;
  192. }
  193. return ntStatus;
  194. }
  195. NTSTATUS
  196. HandleSystemQueryPower(
  197. IN PDEVICE_OBJECT DeviceObject,
  198. IN PIRP Irp
  199. )
  200. /*++
  201. Routine Description:
  202. This routine handles the irp with minor function of type IRP_MN_QUERY_POWER
  203. for the system power states.
  204. Arguments:
  205. DeviceObject - pointer to device object
  206. Irp - I/O request packet sent by the power manager.
  207. Return Value:
  208. NT status value
  209. --*/
  210. {
  211. NTSTATUS ntStatus;
  212. PDEVICE_EXTENSION deviceExtension;
  213. SYSTEM_POWER_STATE systemState;
  214. PIO_STACK_LOCATION irpStack;
  215. SSDbgPrint(3, ("HandleSystemQueryPower - begins\n"));
  216. //
  217. // initialize variables
  218. //
  219. deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  220. irpStack = IoGetCurrentIrpStackLocation(Irp);
  221. systemState = irpStack->Parameters.Power.State.SystemState;
  222. //
  223. // Fail a query for a power state incompatible with waking up the system
  224. //
  225. SSDbgPrint(3, ("Query for a system power state S%X\n"
  226. "Current system power state S%X\n",
  227. systemState - 1,
  228. deviceExtension->SysPower - 1));
  229. //
  230. // if querying for a lower S-state, issue a wait-wake
  231. // also, it is mandatory to have this Irp pending below
  232. // before we send any of the low power irps.
  233. //
  234. if((systemState > deviceExtension->SysPower) &&
  235. (deviceExtension->WaitWakeEnable)) {
  236. IssueWaitWake(deviceExtension);
  237. }
  238. IoCopyCurrentIrpStackLocationToNext(Irp);
  239. IoSetCompletionRoutine(
  240. Irp,
  241. (PIO_COMPLETION_ROUTINE)SysPoCompletionRoutine,
  242. deviceExtension,
  243. TRUE,
  244. TRUE,
  245. TRUE);
  246. ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  247. SSDbgPrint(3, ("HandleSystemQueryPower - ends\n"));
  248. return STATUS_PENDING;
  249. }
  250. NTSTATUS
  251. HandleSystemSetPower(
  252. IN PDEVICE_OBJECT DeviceObject,
  253. IN PIRP Irp
  254. )
  255. /*++
  256. Routine Description:
  257. This routine services irps of minor type IRP_MN_SET_POWER
  258. for the system power state
  259. Arguments:
  260. DeviceObject - pointer to device object
  261. Irp - I/O request packet sent by the power manager
  262. Return Value:
  263. NT status value
  264. --*/
  265. {
  266. NTSTATUS ntStatus;
  267. PDEVICE_EXTENSION deviceExtension;
  268. SYSTEM_POWER_STATE systemState;
  269. PIO_STACK_LOCATION irpStack;
  270. SSDbgPrint(3, ("HandleSystemSetPower - begins\n"));
  271. //
  272. // initialize variables
  273. //
  274. deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  275. irpStack = IoGetCurrentIrpStackLocation(Irp);
  276. systemState = irpStack->Parameters.Power.State.SystemState;
  277. SSDbgPrint(3, ("Set request for a system power state S%X\n"
  278. "Current system power state S%X\n",
  279. systemState - 1,
  280. deviceExtension->SysPower - 1));
  281. //
  282. // pass the irp down the stack
  283. //
  284. IoCopyCurrentIrpStackLocationToNext(Irp);
  285. IoSetCompletionRoutine(
  286. Irp,
  287. (PIO_COMPLETION_ROUTINE)SysPoCompletionRoutine,
  288. deviceExtension,
  289. TRUE,
  290. TRUE,
  291. TRUE);
  292. ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  293. SSDbgPrint(3, ("HandleSystemSetPower - ends\n"));
  294. return STATUS_PENDING;
  295. }
  296. NTSTATUS
  297. HandleDeviceQueryPower(
  298. PDEVICE_OBJECT DeviceObject,
  299. PIRP Irp
  300. )
  301. /*++
  302. Routine Description:
  303. This routine services irps of minor type IRP_MN_QUERY_POWER
  304. for the device power state
  305. Arguments:
  306. DeviceObject - pointer to device object
  307. Irp - I/O request packet sent by the power manager
  308. Return Value:
  309. NT status value
  310. --*/
  311. {
  312. NTSTATUS ntStatus;
  313. PDEVICE_EXTENSION deviceExtension;
  314. PIO_STACK_LOCATION irpStack;
  315. DEVICE_POWER_STATE deviceState;
  316. SSDbgPrint(3, ("HandleDeviceQueryPower - begins\n"));
  317. //
  318. // initialize variables
  319. //
  320. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  321. irpStack = IoGetCurrentIrpStackLocation(Irp);
  322. deviceState = irpStack->Parameters.Power.State.DeviceState;
  323. SSDbgPrint(3, ("Query for a device power state D%X\n"
  324. "Current device power state D%X\n",
  325. deviceState - 1,
  326. deviceExtension->DevPower - 1));
  327. if(deviceState < deviceExtension->DevPower) {
  328. ntStatus = STATUS_SUCCESS;
  329. }
  330. else {
  331. ntStatus = HoldIoRequests(DeviceObject, Irp);
  332. if(STATUS_PENDING == ntStatus) {
  333. return ntStatus;
  334. }
  335. }
  336. //
  337. // on error complete the Irp.
  338. // on success pass it to the lower layers
  339. //
  340. PoStartNextPowerIrp(Irp);
  341. Irp->IoStatus.Status = ntStatus;
  342. Irp->IoStatus.Information = 0;
  343. if(!NT_SUCCESS(ntStatus)) {
  344. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  345. }
  346. else {
  347. IoSkipCurrentIrpStackLocation(Irp);
  348. ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  349. }
  350. SSDbgPrint(3, ("HandleDeviceQueryPower::"));
  351. SSIoDecrement(deviceExtension);
  352. SSDbgPrint(3, ("HandleDeviceQueryPower - ends\n"));
  353. return ntStatus;
  354. }
  355. NTSTATUS
  356. SysPoCompletionRoutine(
  357. IN PDEVICE_OBJECT DeviceObject,
  358. IN PIRP Irp,
  359. IN PDEVICE_EXTENSION DeviceExtension
  360. )
  361. /*++
  362. Routine Description:
  363. This is the completion routine for the system power irps of minor
  364. function types IRP_MN_QUERY_POWER and IRP_MN_SET_POWER.
  365. This completion routine sends the corresponding device power irp and
  366. returns STATUS_MORE_PROCESSING_REQUIRED. The system irp is passed as a
  367. context to the device power irp completion routine and is completed in
  368. the device power irp completion routine.
  369. Arguments:
  370. DeviceObject - pointer to device object
  371. Irp - I/O request packet
  372. DeviceExtension - pointer to device extension
  373. Return Value:
  374. NT status value
  375. --*/
  376. {
  377. NTSTATUS ntStatus;
  378. PIO_STACK_LOCATION irpStack;
  379. //
  380. // initialize variables
  381. //
  382. ntStatus = Irp->IoStatus.Status;
  383. irpStack = IoGetCurrentIrpStackLocation(Irp);
  384. SSDbgPrint(3, ("SysPoCompletionRoutine - begins\n"));
  385. //
  386. // lower drivers failed this Irp
  387. //
  388. if(!NT_SUCCESS(ntStatus)) {
  389. PoStartNextPowerIrp(Irp);
  390. SSDbgPrint(3, ("SysPoCompletionRoutine::"));
  391. SSIoDecrement(DeviceExtension);
  392. return STATUS_SUCCESS;
  393. }
  394. //
  395. // ..otherwise update the cached system power state (IRP_MN_SET_POWER)
  396. //
  397. if(irpStack->MinorFunction == IRP_MN_SET_POWER) {
  398. DeviceExtension->SysPower = irpStack->Parameters.Power.State.SystemState;
  399. }
  400. //
  401. // queue device irp and return STATUS_MORE_PROCESSING_REQUIRED
  402. //
  403. SendDeviceIrp(DeviceObject, Irp);
  404. SSDbgPrint(3, ("SysPoCompletionRoutine - ends\n"));
  405. return STATUS_MORE_PROCESSING_REQUIRED;
  406. }
  407. VOID
  408. SendDeviceIrp(
  409. IN PDEVICE_OBJECT DeviceObject,
  410. IN PIRP SIrp
  411. )
  412. /*++
  413. Routine Description:
  414. This routine is invoked from the completion routine of the system power
  415. irp. This routine will PoRequest a device power irp. The system irp is
  416. passed as a context to the the device power irp.
  417. Arguments:
  418. DeviceObject - pointer to device object
  419. SIrp - system power irp.
  420. Return Value:
  421. None
  422. --*/
  423. {
  424. NTSTATUS ntStatus;
  425. POWER_STATE powState;
  426. PDEVICE_EXTENSION deviceExtension;
  427. PIO_STACK_LOCATION irpStack;
  428. SYSTEM_POWER_STATE systemState;
  429. DEVICE_POWER_STATE devState;
  430. PPOWER_COMPLETION_CONTEXT powerContext;
  431. //
  432. // initialize variables
  433. //
  434. irpStack = IoGetCurrentIrpStackLocation(SIrp);
  435. systemState = irpStack->Parameters.Power.State.SystemState;
  436. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  437. SSDbgPrint(3, ("SendDeviceIrp - begins\n"));
  438. //
  439. // Read out the D-IRP out of the S->D mapping array captured in QueryCap's.
  440. // we can choose deeper sleep states than our mapping but never choose
  441. // lighter ones.
  442. //
  443. devState = deviceExtension->DeviceCapabilities.DeviceState[systemState];
  444. powState.DeviceState = devState;
  445. powerContext = (PPOWER_COMPLETION_CONTEXT)
  446. ExAllocatePool(NonPagedPool,
  447. sizeof(POWER_COMPLETION_CONTEXT));
  448. if(!powerContext) {
  449. SSDbgPrint(1, ("Failed to alloc memory for powerContext\n"));
  450. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  451. }
  452. else {
  453. powerContext->DeviceObject = DeviceObject;
  454. powerContext->SIrp = SIrp;
  455. //
  456. // in win2k PoRequestPowerIrp can take fdo or pdo.
  457. //
  458. ntStatus = PoRequestPowerIrp(
  459. deviceExtension->PhysicalDeviceObject,
  460. irpStack->MinorFunction,
  461. powState,
  462. (PREQUEST_POWER_COMPLETE)DevPoCompletionRoutine,
  463. powerContext,
  464. NULL);
  465. }
  466. if(!NT_SUCCESS(ntStatus)) {
  467. if(powerContext) {
  468. ExFreePool(powerContext);
  469. }
  470. PoStartNextPowerIrp(SIrp);
  471. SIrp->IoStatus.Status = ntStatus;
  472. SIrp->IoStatus.Information = 0;
  473. IoCompleteRequest(SIrp, IO_NO_INCREMENT);
  474. SSDbgPrint(3, ("SendDeviceIrp::"));
  475. SSIoDecrement(deviceExtension);
  476. }
  477. SSDbgPrint(3, ("SendDeviceIrp - ends\n"));
  478. }
  479. VOID
  480. DevPoCompletionRoutine(
  481. IN PDEVICE_OBJECT DeviceObject,
  482. IN UCHAR MinorFunction,
  483. IN POWER_STATE PowerState,
  484. IN PVOID Context,
  485. IN PIO_STATUS_BLOCK IoStatus
  486. )
  487. /*++
  488. Routine Description:
  489. This is the PoRequest - completion routine for the device power irp.
  490. This routine is responsible for completing the system power irp,
  491. received as a context.
  492. Arguments:
  493. DeviceObject - pointer to device object
  494. MinorFunction - minor function of the irp.
  495. PowerState - power state of the irp.
  496. Context - context passed to the completion routine.
  497. IoStatus - status of the device power irp.
  498. Return Value:
  499. None
  500. --*/
  501. {
  502. PIRP sIrp;
  503. PDEVICE_EXTENSION deviceExtension;
  504. PPOWER_COMPLETION_CONTEXT powerContext;
  505. //
  506. // initialize variables
  507. //
  508. powerContext = (PPOWER_COMPLETION_CONTEXT) Context;
  509. sIrp = powerContext->SIrp;
  510. deviceExtension = powerContext->DeviceObject->DeviceExtension;
  511. SSDbgPrint(3, ("DevPoCompletionRoutine - begins\n"));
  512. //
  513. // copy the D-Irp status into S-Irp
  514. //
  515. sIrp->IoStatus.Status = IoStatus->Status;
  516. //
  517. // complete the system Irp
  518. //
  519. PoStartNextPowerIrp(sIrp);
  520. sIrp->IoStatus.Information = 0;
  521. IoCompleteRequest(sIrp, IO_NO_INCREMENT);
  522. //
  523. // cleanup
  524. //
  525. SSDbgPrint(3, ("DevPoCompletionRoutine::"));
  526. SSIoDecrement(deviceExtension);
  527. ExFreePool(powerContext);
  528. SSDbgPrint(3, ("DevPoCompletionRoutine - ends\n"));
  529. }
  530. NTSTATUS
  531. HandleDeviceSetPower(
  532. IN PDEVICE_OBJECT DeviceObject,
  533. IN PIRP Irp
  534. )
  535. /*++
  536. Routine Description:
  537. This routine services irps of minor type IRP_MN_SET_POWER
  538. for the device power state
  539. Arguments:
  540. DeviceObject - pointer to device object
  541. Irp - I/O request packet sent by the power manager
  542. Return Value:
  543. NT status value
  544. --*/
  545. {
  546. KIRQL oldIrql;
  547. NTSTATUS ntStatus;
  548. POWER_STATE newState;
  549. PIO_STACK_LOCATION irpStack;
  550. PDEVICE_EXTENSION deviceExtension;
  551. DEVICE_POWER_STATE newDevState,
  552. oldDevState;
  553. SSDbgPrint(3, ("HandleDeviceSetPower - begins\n"));
  554. //
  555. // initialize variables
  556. //
  557. deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  558. irpStack = IoGetCurrentIrpStackLocation(Irp);
  559. oldDevState = deviceExtension->DevPower;
  560. newState = irpStack->Parameters.Power.State;
  561. newDevState = newState.DeviceState;
  562. SSDbgPrint(3, ("Set request for a device power state D%X\n"
  563. "Current device power state D%X\n",
  564. newDevState - 1,
  565. deviceExtension->DevPower - 1));
  566. if(newDevState < oldDevState) {
  567. //
  568. // adding power
  569. //
  570. SSDbgPrint(3, ("Adding power to the device\n"));
  571. //
  572. // send the power IRP to the next driver in the stack
  573. //
  574. IoCopyCurrentIrpStackLocationToNext(Irp);
  575. IoSetCompletionRoutine(
  576. Irp,
  577. (PIO_COMPLETION_ROUTINE)FinishDevPoUpIrp,
  578. deviceExtension,
  579. TRUE,
  580. TRUE,
  581. TRUE);
  582. ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  583. }
  584. else {
  585. //
  586. // newDevState >= oldDevState
  587. //
  588. // hold I/O if transition from D0 -> DX (X = 1, 2, 3)
  589. // if transition from D1 or D2 to deeper sleep states,
  590. // I/O queue is already on hold.
  591. //
  592. if(PowerDeviceD0 == oldDevState && newDevState > oldDevState) {
  593. //
  594. // D0 -> DX transition
  595. //
  596. SSDbgPrint(3, ("Removing power from the device\n"))
  597. ntStatus = HoldIoRequests(DeviceObject, Irp);
  598. if(!NT_SUCCESS(ntStatus)) {
  599. PoStartNextPowerIrp(Irp);
  600. Irp->IoStatus.Status = ntStatus;
  601. Irp->IoStatus.Information = 0;
  602. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  603. SSDbgPrint(3, ("HandleDeviceSetPower::"));
  604. SSIoDecrement(deviceExtension);
  605. return ntStatus;
  606. }
  607. else {
  608. goto HandleDeviceSetPower_Exit;
  609. }
  610. }
  611. else if(PowerDeviceD0 == oldDevState && PowerDeviceD0 == newDevState) {
  612. //
  613. // D0 -> D0
  614. // unblock the queue which may have been blocked processing
  615. // query irp
  616. //
  617. SSDbgPrint(3, ("A SetD0 power request for the device\n"))
  618. KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
  619. deviceExtension->QueueState = AllowRequests;
  620. KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
  621. ProcessQueuedRequests(deviceExtension);
  622. }
  623. IoCopyCurrentIrpStackLocationToNext(Irp);
  624. IoSetCompletionRoutine(
  625. Irp,
  626. (PIO_COMPLETION_ROUTINE) FinishDevPoDnIrp,
  627. deviceExtension,
  628. TRUE,
  629. TRUE,
  630. TRUE);
  631. ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  632. if(!NT_SUCCESS(ntStatus)) {
  633. SSDbgPrint(1, ("Lower drivers failed a power Irp\n"));
  634. }
  635. }
  636. HandleDeviceSetPower_Exit:
  637. SSDbgPrint(3, ("HandleDeviceSetPower - ends\n"));
  638. return STATUS_PENDING;
  639. }
  640. NTSTATUS
  641. FinishDevPoUpIrp(
  642. IN PDEVICE_OBJECT DeviceObject,
  643. IN PIRP Irp,
  644. IN PDEVICE_EXTENSION DeviceExtension
  645. )
  646. /*++
  647. Routine Description:
  648. completion routine for the device power UP irp with minor function
  649. IRP_MN_SET_POWER.
  650. Arguments:
  651. DeviceObject - pointer to device object
  652. Irp - I/O request packet
  653. DeviceExtension - pointer to device extension
  654. Return Value:
  655. NT status value
  656. --*/
  657. {
  658. NTSTATUS ntStatus;
  659. //
  660. // initialize variables
  661. //
  662. ntStatus = Irp->IoStatus.Status;
  663. SSDbgPrint(3, ("FinishDevPoUpIrp - begins\n"));
  664. if(Irp->PendingReturned) {
  665. IoMarkIrpPending(Irp);
  666. }
  667. if(!NT_SUCCESS(ntStatus)) {
  668. PoStartNextPowerIrp(Irp);
  669. SSDbgPrint(3, ("FinishDevPoUpIrp::"));
  670. SSIoDecrement(DeviceExtension);
  671. return STATUS_SUCCESS;
  672. }
  673. SetDeviceFunctional(DeviceObject, Irp, DeviceExtension);
  674. SSDbgPrint(3, ("FinishDevPoUpIrp - ends\n"));
  675. return STATUS_MORE_PROCESSING_REQUIRED;
  676. }
  677. NTSTATUS
  678. SetDeviceFunctional(
  679. IN PDEVICE_OBJECT DeviceObject,
  680. IN PIRP Irp,
  681. IN PDEVICE_EXTENSION DeviceExtension
  682. )
  683. /*++
  684. Routine Description:
  685. This routine processes queue of pending irps.
  686. Arguments:
  687. DeviceObject - pointer to device object
  688. Irp - I/O request packet
  689. DeviceExtension - pointer to device extension
  690. Return Value:
  691. NT status value
  692. --*/
  693. {
  694. KIRQL oldIrql;
  695. NTSTATUS ntStatus;
  696. POWER_STATE newState;
  697. PIO_STACK_LOCATION irpStack;
  698. DEVICE_POWER_STATE newDevState,
  699. oldDevState;
  700. //
  701. // initialize variables
  702. //
  703. ntStatus = Irp->IoStatus.Status;
  704. irpStack = IoGetCurrentIrpStackLocation(Irp);
  705. newState = irpStack->Parameters.Power.State;
  706. newDevState = newState.DeviceState;
  707. oldDevState = DeviceExtension->DevPower;
  708. SSDbgPrint(3, ("SetDeviceFunctional - begins\n"));
  709. //
  710. // update the cached state
  711. //
  712. DeviceExtension->DevPower = newDevState;
  713. //
  714. // restore appropriate amount of state to our h/w
  715. // this driver does not implement partial context
  716. // save/restore.
  717. //
  718. PoSetPowerState(DeviceObject, DevicePowerState, newState);
  719. if(PowerDeviceD0 == newDevState) {
  720. //
  721. // empty existing queue of all pending irps.
  722. //
  723. KeAcquireSpinLock(&DeviceExtension->DevStateLock, &oldIrql);
  724. DeviceExtension->QueueState = AllowRequests;
  725. KeReleaseSpinLock(&DeviceExtension->DevStateLock, oldIrql);
  726. ProcessQueuedRequests(DeviceExtension);
  727. }
  728. PoStartNextPowerIrp(Irp);
  729. Irp->IoStatus.Status = STATUS_SUCCESS;
  730. Irp->IoStatus.Information = 0;
  731. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  732. SSDbgPrint(3, ("SetDeviceFunctional::"));
  733. SSIoDecrement(DeviceExtension);
  734. SSDbgPrint(3, ("SetDeviceFunctional - ends\n"));
  735. return STATUS_SUCCESS;
  736. }
  737. NTSTATUS
  738. FinishDevPoDnIrp(
  739. IN PDEVICE_OBJECT DeviceObject,
  740. IN PIRP Irp,
  741. IN PDEVICE_EXTENSION DeviceExtension
  742. )
  743. /*++
  744. Routine Description:
  745. This routine is the completion routine for device power DOWN irp.
  746. Arguments:
  747. DeviceObject - pointer to device object
  748. Irp - I/O request packet
  749. DeviceExtension - pointer to device extension
  750. Return Value:
  751. NT status value
  752. --*/
  753. {
  754. NTSTATUS ntStatus;
  755. POWER_STATE newState;
  756. PIO_STACK_LOCATION irpStack;
  757. //
  758. // initialize variables
  759. //
  760. ntStatus = Irp->IoStatus.Status;
  761. irpStack = IoGetCurrentIrpStackLocation(Irp);
  762. newState = irpStack->Parameters.Power.State;
  763. SSDbgPrint(3, ("FinishDevPoDnIrp - begins\n"));
  764. if(NT_SUCCESS(ntStatus) && irpStack->MinorFunction == IRP_MN_SET_POWER) {
  765. //
  766. // update the cache;
  767. //
  768. SSDbgPrint(3, ("updating cache..\n"));
  769. DeviceExtension->DevPower = newState.DeviceState;
  770. PoSetPowerState(DeviceObject, DevicePowerState, newState);
  771. }
  772. PoStartNextPowerIrp(Irp);
  773. SSDbgPrint(3, ("FinishDevPoDnIrp::"));
  774. SSIoDecrement(DeviceExtension);
  775. SSDbgPrint(3, ("FinishDevPoDnIrp - ends\n"));
  776. return STATUS_SUCCESS;
  777. }
  778. NTSTATUS
  779. HoldIoRequests(
  780. IN PDEVICE_OBJECT DeviceObject,
  781. IN PIRP Irp
  782. )
  783. /*++
  784. Routine Description:
  785. This routine is called on query or set power DOWN irp for the device.
  786. This routine queues a workitem.
  787. Arguments:
  788. DeviceObject - pointer to device object
  789. Irp - I/O request packet
  790. Return Value:
  791. NT status value
  792. --*/
  793. {
  794. NTSTATUS ntStatus;
  795. PIO_WORKITEM item;
  796. PDEVICE_EXTENSION deviceExtension;
  797. PWORKER_THREAD_CONTEXT context;
  798. //
  799. // initialize variables
  800. //
  801. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  802. SSDbgPrint(3, ("HoldIoRequests - begins\n"));
  803. deviceExtension->QueueState = HoldRequests;
  804. context = ExAllocatePool(NonPagedPool, sizeof(WORKER_THREAD_CONTEXT));
  805. if(context) {
  806. item = IoAllocateWorkItem(DeviceObject);
  807. context->Irp = Irp;
  808. context->DeviceObject = DeviceObject;
  809. context->WorkItem = item;
  810. if(item) {
  811. IoMarkIrpPending(Irp);
  812. IoQueueWorkItem(item, HoldIoRequestsWorkerRoutine,
  813. DelayedWorkQueue, context);
  814. ntStatus = STATUS_PENDING;
  815. }
  816. else {
  817. SSDbgPrint(3, ("Failed to allocate memory for workitem\n"));
  818. ExFreePool(context);
  819. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  820. }
  821. }
  822. else {
  823. SSDbgPrint(1, ("Failed to alloc memory for worker thread context\n"));
  824. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  825. }
  826. SSDbgPrint(3, ("HoldIoRequests - ends\n"));
  827. return ntStatus;
  828. }
  829. VOID
  830. HoldIoRequestsWorkerRoutine(
  831. IN PDEVICE_OBJECT DeviceObject,
  832. IN PVOID Context
  833. )
  834. /*++
  835. Routine Description:
  836. This routine waits for the I/O in progress to finish and then
  837. sends the device power irp (query/set) down the stack.
  838. Arguments:
  839. DeviceObject - pointer to device object
  840. Context - context passed to the work-item.
  841. Return Value:
  842. None
  843. --*/
  844. {
  845. PIRP irp;
  846. NTSTATUS ntStatus;
  847. PDEVICE_EXTENSION deviceExtension;
  848. PWORKER_THREAD_CONTEXT context;
  849. SSDbgPrint(3, ("HoldIoRequestsWorkerRoutine - begins\n"));
  850. //
  851. // initialize variables
  852. //
  853. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  854. context = (PWORKER_THREAD_CONTEXT) Context;
  855. irp = (PIRP) context->Irp;
  856. //
  857. // wait for I/O in progress to finish.
  858. // the stop event is signalled when the counter drops to 1.
  859. // invoke SSIoDecrement twice: once each for the S-Irp and D-Irp.
  860. //
  861. SSDbgPrint(3, ("HoldIoRequestsWorkerRoutine::"));
  862. SSIoDecrement(deviceExtension);
  863. SSDbgPrint(3, ("HoldIoRequestsWorkerRoutine::"));
  864. SSIoDecrement(deviceExtension);
  865. KeWaitForSingleObject(&deviceExtension->StopEvent, Executive,
  866. KernelMode, FALSE, NULL);
  867. //
  868. // Increment twice to restore the count
  869. //
  870. SSDbgPrint(3, ("HoldIoRequestsWorkerRoutine::"));
  871. SSIoIncrement(deviceExtension);
  872. SSDbgPrint(3, ("HoldIoRequestsWorkerRoutine::"));
  873. SSIoIncrement(deviceExtension);
  874. //
  875. // now send the Irp down
  876. //
  877. IoCopyCurrentIrpStackLocationToNext(irp);
  878. IoSetCompletionRoutine(irp, (PIO_COMPLETION_ROUTINE) FinishDevPoDnIrp,
  879. deviceExtension, TRUE, TRUE, TRUE);
  880. ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
  881. if(!NT_SUCCESS(ntStatus)) {
  882. SSDbgPrint(1, ("Lower driver fail a power Irp\n"));
  883. }
  884. IoFreeWorkItem(context->WorkItem);
  885. ExFreePool((PVOID)context);
  886. SSDbgPrint(3, ("HoldIoRequestsWorkerRoutine - ends\n"));
  887. }
  888. NTSTATUS
  889. QueueRequest(
  890. IN OUT PDEVICE_EXTENSION DeviceExtension,
  891. IN PIRP Irp
  892. )
  893. /*++
  894. Routine Description:
  895. Queue the Irp in the device queue
  896. Arguments:
  897. DeviceExtension - pointer to device extension
  898. Irp - I/O request packet.
  899. Return Value:
  900. NT status value
  901. --*/
  902. {
  903. KIRQL oldIrql;
  904. NTSTATUS ntStatus;
  905. //
  906. // initialize variables
  907. //
  908. ntStatus = STATUS_PENDING;
  909. SSDbgPrint(3, ("QueueRequests - begins\n"));
  910. ASSERT(HoldRequests == DeviceExtension->QueueState);
  911. KeAcquireSpinLock(&DeviceExtension->QueueLock, &oldIrql);
  912. InsertTailList(&DeviceExtension->NewRequestsQueue,
  913. &Irp->Tail.Overlay.ListEntry);
  914. IoMarkIrpPending(Irp);
  915. //
  916. // Set the cancel routine
  917. //
  918. IoSetCancelRoutine(Irp, CancelQueued);
  919. KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
  920. SSDbgPrint(3, ("QueueRequests - ends\n"));
  921. return ntStatus;
  922. }
  923. VOID
  924. CancelQueued(
  925. IN PDEVICE_OBJECT DeviceObject,
  926. IN PIRP Irp
  927. )
  928. /*++
  929. Routine Description:
  930. This routine removes the irp from the queue and completes it with
  931. STATUS_CANCELLED
  932. Arguments:
  933. DeviceObject - pointer to device object
  934. Irp - I/O request packet
  935. Return Value:
  936. None.
  937. --*/
  938. {
  939. PDEVICE_EXTENSION deviceExtension;
  940. KIRQL oldIrql;
  941. //
  942. // initialize variables
  943. //
  944. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  945. oldIrql = Irp->CancelIrql;
  946. SSDbgPrint(3, ("CancelQueued - begins\n"));
  947. //
  948. // Release the cancel spin lock
  949. //
  950. IoReleaseCancelSpinLock(Irp->CancelIrql);
  951. //
  952. // Acquire the queue lock
  953. //
  954. KeAcquireSpinLockAtDpcLevel(&deviceExtension->QueueLock);
  955. //
  956. // Remove the cancelled Irp from queue and release the lock
  957. //
  958. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  959. KeReleaseSpinLock(&deviceExtension->QueueLock, oldIrql);
  960. //
  961. // complete with STATUS_CANCELLED
  962. //
  963. Irp->IoStatus.Status = STATUS_CANCELLED;
  964. Irp->IoStatus.Information = 0;
  965. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  966. SSDbgPrint(3, ("CancelQueued - ends\n"));
  967. return;
  968. }
  969. NTSTATUS
  970. IssueWaitWake(
  971. IN PDEVICE_EXTENSION DeviceExtension
  972. )
  973. /*++
  974. Routine Description:
  975. This routine will PoRequest a WAIT WAKE irp for the device
  976. Arguments:
  977. DeviceExtension - pointer to device extension
  978. Return Value:
  979. NT status value.
  980. --*/
  981. {
  982. POWER_STATE poState;
  983. NTSTATUS ntStatus;
  984. SSDbgPrint(3, ("IssueWaitWake - begins\n"));
  985. if(InterlockedExchange(&DeviceExtension->FlagWWOutstanding, 1)) {
  986. SSDbgPrint(3, ("Outstanding wait wake Irp\n"));
  987. return STATUS_DEVICE_BUSY;
  988. }
  989. InterlockedExchange(&DeviceExtension->FlagWWCancel, 0);
  990. //
  991. // lowest state from which this Irp will wake the system
  992. //
  993. poState.SystemState = DeviceExtension->DeviceCapabilities.SystemWake;
  994. ntStatus = PoRequestPowerIrp(DeviceExtension->PhysicalDeviceObject,
  995. IRP_MN_WAIT_WAKE,
  996. poState,
  997. (PREQUEST_POWER_COMPLETE) WaitWakeCallback,
  998. DeviceExtension,
  999. &DeviceExtension->WaitWakeIrp);
  1000. if(!NT_SUCCESS(ntStatus)) {
  1001. InterlockedExchange(&DeviceExtension->FlagWWOutstanding, 0);
  1002. }
  1003. SSDbgPrint(3, ("IssueWaitWake - ends\n"));
  1004. return ntStatus;
  1005. }
  1006. VOID
  1007. CancelWaitWake(
  1008. IN PDEVICE_EXTENSION DeviceExtension
  1009. )
  1010. /*++
  1011. Routine Description:
  1012. This routine cancels the Wait Wake request.
  1013. Arguments:
  1014. DeviceExtension - pointer to the device extension
  1015. Return Value:
  1016. None.
  1017. --*/
  1018. {
  1019. PIRP Irp;
  1020. SSDbgPrint(3, ("CancelWaitWake - begins\n"));
  1021. Irp = (PIRP) InterlockedExchangePointer(&DeviceExtension->WaitWakeIrp,
  1022. NULL);
  1023. if(Irp) {
  1024. IoCancelIrp(Irp);
  1025. if(InterlockedExchange(&DeviceExtension->FlagWWCancel, 1)) {
  1026. PoStartNextPowerIrp(Irp);
  1027. Irp->IoStatus.Status = STATUS_CANCELLED;
  1028. Irp->IoStatus.Information = 0;
  1029. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1030. }
  1031. }
  1032. SSDbgPrint(3, ("CancelWaitWake - ends\n"));
  1033. }
  1034. NTSTATUS
  1035. WaitWakeCompletionRoutine(
  1036. IN PDEVICE_OBJECT DeviceObject,
  1037. IN PIRP Irp,
  1038. IN PDEVICE_EXTENSION DeviceExtension
  1039. )
  1040. /*++
  1041. Routine Description:
  1042. This is the IoSet completion routine for the wait wake irp.
  1043. Arguments:
  1044. DeviceObject - pointer to device object
  1045. Irp - I/O request packet
  1046. DeviceExtension - pointer to device extension
  1047. Return Value:
  1048. NT status value
  1049. --*/
  1050. {
  1051. SSDbgPrint(3, ("WaitWakeCompletionRoutine - begins\n"));
  1052. if(Irp->PendingReturned) {
  1053. IoMarkIrpPending(Irp);
  1054. }
  1055. //
  1056. // Nullify the WaitWakeIrp pointer-the Irp is released
  1057. // as part of the completion process. If it's already NULL,
  1058. // avoid race with the CancelWaitWake routine.
  1059. //
  1060. if(InterlockedExchangePointer(&DeviceExtension->WaitWakeIrp, NULL)) {
  1061. PoStartNextPowerIrp(Irp);
  1062. return STATUS_SUCCESS;
  1063. }
  1064. //
  1065. // CancelWaitWake has run.
  1066. // If FlagWWCancel != 0, complete the Irp.
  1067. // If FlagWWCancel == 0, CancelWaitWake completes it.
  1068. //
  1069. if(InterlockedExchange(&DeviceExtension->FlagWWCancel, 1)) {
  1070. PoStartNextPowerIrp(Irp);
  1071. return STATUS_CANCELLED;
  1072. }
  1073. SSDbgPrint(3, ("WaitWakeCompletionRoutine - ends\n"));
  1074. return STATUS_MORE_PROCESSING_REQUIRED;
  1075. }
  1076. VOID
  1077. WaitWakeCallback(
  1078. IN PDEVICE_OBJECT DeviceObject,
  1079. IN UCHAR MinorFunction,
  1080. IN POWER_STATE PowerState,
  1081. IN PVOID Context,
  1082. IN PIO_STATUS_BLOCK IoStatus
  1083. )
  1084. /*++
  1085. Routine Description:
  1086. This is the PoRequest completion routine for the wait wake irp.
  1087. Arguments:
  1088. DeviceObject - pointer to device object
  1089. MinorFunction - irp minor function
  1090. PowerState - power state of the irp.
  1091. Context - context passed to the completion routine.
  1092. IoStatus - status block.
  1093. Return Value:
  1094. None
  1095. --*/
  1096. {
  1097. NTSTATUS ntStatus;
  1098. POWER_STATE powerState;
  1099. PDEVICE_EXTENSION deviceExtension;
  1100. SSDbgPrint(3, ("WaitWakeCallback - begins\n"));
  1101. deviceExtension = (PDEVICE_EXTENSION) Context;
  1102. InterlockedExchange(&deviceExtension->FlagWWOutstanding, 0);
  1103. if(!NT_SUCCESS(IoStatus->Status)) {
  1104. return;
  1105. }
  1106. //
  1107. // wake up the device
  1108. //
  1109. if(deviceExtension->DevPower == PowerDeviceD0) {
  1110. SSDbgPrint(3, ("device already powered up...\n"));
  1111. return;
  1112. }
  1113. SSDbgPrint(3, ("WaitWakeCallback::"));
  1114. SSIoIncrement(deviceExtension);
  1115. powerState.DeviceState = PowerDeviceD0;
  1116. ntStatus = PoRequestPowerIrp(deviceExtension->PhysicalDeviceObject,
  1117. IRP_MN_SET_POWER,
  1118. powerState,
  1119. (PREQUEST_POWER_COMPLETE) WWIrpCompletionFunc,
  1120. deviceExtension,
  1121. NULL);
  1122. if(deviceExtension->WaitWakeEnable) {
  1123. IssueWaitWake(deviceExtension);
  1124. }
  1125. SSDbgPrint(3, ("WaitWakeCallback - ends\n"));
  1126. return;
  1127. }
  1128. PCHAR
  1129. PowerMinorFunctionString (
  1130. IN UCHAR MinorFunction
  1131. )
  1132. /*++
  1133. Routine Description:
  1134. Arguments:
  1135. Return Value:
  1136. --*/
  1137. {
  1138. switch (MinorFunction) {
  1139. case IRP_MN_SET_POWER:
  1140. return "IRP_MN_SET_POWER\n";
  1141. case IRP_MN_QUERY_POWER:
  1142. return "IRP_MN_QUERY_POWER\n";
  1143. case IRP_MN_POWER_SEQUENCE:
  1144. return "IRP_MN_POWER_SEQUENCE\n";
  1145. case IRP_MN_WAIT_WAKE:
  1146. return "IRP_MN_WAIT_WAKE\n";
  1147. default:
  1148. return "IRP_MN_?????\n";
  1149. }
  1150. }