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.

1205 lines
32 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved
  3. Module Name:
  4. power.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. The power policy of this driver is simple. The device enters the
  22. device working state D0 when the system enters the system
  23. working state S0. The device enters the lowest-powered sleeping state
  24. D3 for all the other system power states (S1-S5).
  25. Environment:
  26. Kernel mode
  27. Revision History:
  28. --*/
  29. #include "processor.h"
  30. #include "power.h"
  31. PVOID ProcessorSleepPageLock = NULL;
  32. AC_DC_TRANSITION_NOTIFY AcDcTransitionNotifyHandler;
  33. #ifdef ALLOC_PRAGMA
  34. #pragma alloc_text (PAGELK, ProcessorDispatchPower)
  35. #pragma alloc_text (PAGELK, ProcessorDefaultPowerHandler)
  36. #pragma alloc_text (PAGELK, ProcessorSetPowerState)
  37. #pragma alloc_text (PAGELK, ProcessorQueryPowerState)
  38. #pragma alloc_text (PAGELK, HandleSystemPowerIrp)
  39. #pragma alloc_text (PAGELK, OnFinishSystemPowerUp)
  40. #pragma alloc_text (PAGELK, QueueCorrespondingDeviceIrp)
  41. #pragma alloc_text (PAGELK, OnPowerRequestComplete)
  42. #pragma alloc_text (PAGELK, HandleDeviceQueryPower)
  43. #pragma alloc_text (PAGELK, HandleDeviceSetPower)
  44. #pragma alloc_text (PAGELK, OnFinishDevicePowerUp)
  45. #pragma alloc_text (PAGELK, BeginSetDevicePowerState)
  46. #pragma alloc_text (PAGELK, FinishDevicePowerIrp)
  47. #pragma alloc_text (PAGELK, HoldIoRequests)
  48. #pragma alloc_text (PAGELK, HoldIoRequestsWorkerRoutine)
  49. #pragma alloc_text (PAGELK, ProcessorPowerStateCallback)
  50. #pragma alloc_text (PAGELK, RegisterAcDcTransitionNotifyHandler)
  51. #endif
  52. NTSTATUS
  53. ProcessorDispatchPower (
  54. IN PDEVICE_OBJECT DeviceObject,
  55. IN PIRP Irp
  56. )
  57. /*++
  58. Routine Description:
  59. The power dispatch routine.
  60. Arguments:
  61. DeviceObject - pointer to a device object.
  62. Irp - pointer to an I/O Request Packet.
  63. Return Value:
  64. NT status code
  65. --*/
  66. {
  67. PIO_STACK_LOCATION stack;
  68. PFDO_DATA fdoData;
  69. NTSTATUS status;
  70. DebugEnter();
  71. stack = IoGetCurrentIrpStackLocation(Irp);
  72. fdoData = (PFDO_DATA) DeviceObject->DeviceExtension;
  73. DebugPrint((TRACE, "FDO %s IRP:0x%x %s %s\n",
  74. PowerMinorFunctionString(stack->MinorFunction),
  75. Irp,
  76. DbgSystemPowerString(fdoData->SystemPowerState),
  77. DbgDevicePowerString(fdoData->DevicePowerState)));
  78. //
  79. // We don't queue power Irps, we'll only check if the
  80. // device was removed, otherwise we'll take appropriate
  81. // action and send it to the next lower driver. In general
  82. // drivers should not cause long delays while handling power
  83. // IRPs. If a driver cannot handle a power IRP in a brief time,
  84. // it should return STATUS_PENDING and queue all incoming
  85. // IRPs until the IRP completes.
  86. //
  87. if (Deleted == fdoData->DevicePnPState) {
  88. //
  89. // Even if a driver fails the IRP, it must nevertheless call
  90. // PoStartNextPowerIrp to inform the Power Manager that it
  91. // is ready to handle another power IRP.
  92. //
  93. PoStartNextPowerIrp (Irp);
  94. Irp->IoStatus.Status = status = STATUS_DELETE_PENDING;
  95. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  96. return status;
  97. }
  98. //
  99. // If the device is not stated yet, just pass it down.
  100. //
  101. if (NotStarted == fdoData->DevicePnPState ) {
  102. PoStartNextPowerIrp(Irp);
  103. IoSkipCurrentIrpStackLocation(Irp);
  104. return PoCallDriver(fdoData->NextLowerDriver, Irp);
  105. }
  106. ProcessorIoIncrement (fdoData);
  107. //
  108. // Check the request type.
  109. //
  110. switch (stack->MinorFunction) {
  111. case IRP_MN_SET_POWER :
  112. //
  113. // The Power Manager sends this IRP for one of the
  114. // following reasons:
  115. // 1) To notify drivers of a change to the system power state.
  116. // 2) To change the power state of a device for which
  117. // the Power Manager is performing idle detection.
  118. // A driver sends IRP_MN_SET_POWER to change the power
  119. // state of its device if it's a power policy owner for the
  120. // device.
  121. //
  122. status = ProcessorSetPowerState(DeviceObject, Irp);
  123. break;
  124. case IRP_MN_QUERY_POWER :
  125. //
  126. // The Power Manager sends a power IRP with the minor
  127. // IRP code IRP_MN_QUERY_POWER to determine whether it
  128. // can safely change to the specified system power state
  129. // (S1-S5) and to allow drivers to prepare for such a change.
  130. // If a driver can put its device in the requested state,
  131. // it sets status to STATUS_SUCCESS and passes the IRP down.
  132. //
  133. status = ProcessorQueryPowerState(DeviceObject, Irp);
  134. break;
  135. case IRP_MN_WAIT_WAKE :
  136. //
  137. // The minor power IRP code IRP_MN_WAIT_WAKE provides
  138. // for waking a device or waking the system. Drivers
  139. // of devices that can wake themselves or the system
  140. // send IRP_MN_WAIT_WAKE. The system sends IRP_MN_WAIT_WAKE
  141. // only to devices that always wake the system, such as
  142. // the power-on switch.
  143. //
  144. case IRP_MN_POWER_SEQUENCE :
  145. //
  146. // A driver sends this IRP as an optimization to determine
  147. // whether its device actually entered a specific power state.
  148. // This IRP is optional. Power Manager cannot send this IRP.
  149. //
  150. default:
  151. //
  152. // Pass it down
  153. //
  154. status = ProcessorDefaultPowerHandler(DeviceObject, Irp);
  155. ProcessorIoDecrement(fdoData);
  156. break;
  157. }
  158. return status;
  159. }
  160. NTSTATUS
  161. ProcessorDefaultPowerHandler (
  162. IN PDEVICE_OBJECT DeviceObject,
  163. IN OUT PIRP Irp
  164. )
  165. /*++
  166. Routine Description:
  167. If a driver does not support a particular power IRP,
  168. it must nevertheless pass the IRP down the device stack
  169. to the next-lower driver. A driver further down the stack
  170. might be prepared to handle the IRP and must have the
  171. opportunity to do so.
  172. Arguments:
  173. DeviceObject - pointer to a device object.
  174. Irp - pointer to an I/O Request Packet.
  175. Return Value:
  176. NT status code
  177. --*/
  178. {
  179. NTSTATUS status;
  180. PFDO_DATA fdoData;
  181. DebugEnter();
  182. //
  183. // Drivers must call PoStartNextPowerIrp while the current
  184. // IRP stack location points to the current driver.
  185. // This routine can be called from the DispatchPower routine
  186. // or from the IoCompletion routine. However, PoStartNextPowerIrp
  187. // must be called before IoCompleteRequest, IoSkipCurrentIrpStackLocation,
  188. // and PoCallDriver. Calling the routines in the other order might
  189. // cause a system deadlock.
  190. //
  191. PoStartNextPowerIrp(Irp);
  192. IoSkipCurrentIrpStackLocation(Irp);
  193. fdoData = (PFDO_DATA)DeviceObject->DeviceExtension;
  194. //
  195. // Drivers must use PoCallDriver, rather than IoCallDriver,
  196. // to pass power IRPs. PoCallDriver allows the Power Manager
  197. // to ensure that power IRPs are properly synchronized throughout
  198. // the system.
  199. //
  200. status = PoCallDriver(fdoData->NextLowerDriver, Irp);
  201. if (!NT_SUCCESS(status)) {
  202. DebugPrint((0, "Lower driver fails a power irp\n"));
  203. }
  204. return status;
  205. }
  206. NTSTATUS
  207. ProcessorSetPowerState(
  208. IN PDEVICE_OBJECT DeviceObject,
  209. IN PIRP Irp
  210. )
  211. /*++
  212. Routine Description:
  213. Processes IRP_MN_SET_POWER.
  214. Arguments:
  215. DeviceObject - pointer to a device object.
  216. Irp - pointer to an I/O Request Packet.
  217. Return Value:
  218. NT status code
  219. --*/
  220. {
  221. PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
  222. DebugEnter();
  223. return (stack->Parameters.Power.Type == SystemPowerState) ?
  224. HandleSystemPowerIrp(DeviceObject, Irp) :
  225. HandleDeviceSetPower(DeviceObject, Irp);
  226. }
  227. NTSTATUS
  228. ProcessorQueryPowerState(
  229. IN PDEVICE_OBJECT DeviceObject,
  230. IN PIRP Irp
  231. )
  232. /*++
  233. Routine Description:
  234. Processes IRP_MN_QUERY_POWER.
  235. Arguments:
  236. DeviceObject - pointer to a device object.
  237. Irp - pointer to an I/O Request Packet.
  238. Return Value:
  239. NT status code
  240. --*/
  241. {
  242. PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
  243. DebugEnter();
  244. return (stack->Parameters.Power.Type == SystemPowerState) ?
  245. HandleSystemPowerIrp(DeviceObject, Irp) :
  246. HandleDeviceQueryPower(DeviceObject, Irp);
  247. }
  248. NTSTATUS
  249. HandleSystemPowerIrp(
  250. IN PDEVICE_OBJECT DeviceObject,
  251. IN PIRP Irp
  252. )
  253. /*++
  254. Routine Description:
  255. Processes IRP_MN_SET_POWER and IRP_MN_QUERY_POWER
  256. for the system power Irp (S-IRP).
  257. Arguments:
  258. DeviceObject - pointer to a device object.
  259. Irp - pointer to an I/O Request Packet.
  260. Return Value:
  261. NT status code
  262. --*/
  263. {
  264. PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
  265. POWER_STATE_TYPE type = stack->Parameters.Power.Type;
  266. PFDO_DATA fdoData = (PFDO_DATA) DeviceObject->DeviceExtension;
  267. SYSTEM_POWER_STATE newSystemState;
  268. DebugEnter();
  269. IoMarkIrpPending(Irp);
  270. newSystemState = stack->Parameters.Power.State.SystemState;
  271. //
  272. // Here we update our cached away system power state.
  273. //
  274. if (stack->MinorFunction == IRP_MN_SET_POWER) {
  275. //
  276. // We are suspending ...
  277. //
  278. if (newSystemState > PowerSystemWorking &&
  279. newSystemState < PowerSystemShutdown) {
  280. ProcessSuspendToSleepState(newSystemState, fdoData);
  281. }
  282. //
  283. // We are resuming ...
  284. //
  285. if (newSystemState == PowerSystemWorking) {
  286. ProcessResumeFromSleepState(fdoData->SystemPowerState, fdoData);
  287. }
  288. fdoData->SystemPowerState = newSystemState;
  289. }
  290. //
  291. // Send the IRP down
  292. //
  293. IoCopyCurrentIrpStackLocationToNext(Irp);
  294. IoSetCompletionRoutine(Irp,
  295. (PIO_COMPLETION_ROUTINE) OnFinishSystemPowerUp,
  296. NULL,
  297. TRUE,
  298. TRUE,
  299. TRUE);
  300. PoCallDriver(fdoData->NextLowerDriver, Irp);
  301. return STATUS_PENDING;
  302. }
  303. NTSTATUS
  304. OnFinishSystemPowerUp(
  305. IN PDEVICE_OBJECT Fdo,
  306. IN PIRP Irp,
  307. IN PVOID NotUsed
  308. )
  309. /*++
  310. Routine Description:
  311. The completion routine for Power Up S-IRP.
  312. It queues a corresponding D-IRP.
  313. Arguments:
  314. DeviceObject - pointer to a device object.
  315. Irp - pointer to an I/O Request Packet.
  316. Not used - context pointer
  317. Return Value:
  318. NT status code
  319. --*/
  320. {
  321. PFDO_DATA fdoData = (PFDO_DATA) Fdo->DeviceExtension;
  322. NTSTATUS status = Irp->IoStatus.Status;
  323. DebugEnter();
  324. if (!NT_SUCCESS(status)) {
  325. PoStartNextPowerIrp(Irp);
  326. ProcessorIoDecrement(fdoData);
  327. return STATUS_SUCCESS;
  328. }
  329. QueueCorrespondingDeviceIrp(Irp, Fdo);
  330. return STATUS_MORE_PROCESSING_REQUIRED;
  331. }
  332. VOID
  333. QueueCorrespondingDeviceIrp(
  334. IN PIRP SIrp,
  335. IN PDEVICE_OBJECT DeviceObject
  336. )
  337. /*++
  338. Routine Description:
  339. This routine gets the D-State for a particular S-State
  340. from DeviceCaps and generates a D-IRP.
  341. Arguments:
  342. Irp - pointer to an S-IRP.
  343. DeviceObject - pointer to a device object.
  344. Return Value:
  345. --*/
  346. {
  347. POWER_COMPLETION_CONTEXT* powerContext;
  348. NTSTATUS status;
  349. POWER_STATE state;
  350. PFDO_DATA fdoData = (PFDO_DATA) DeviceObject->DeviceExtension;
  351. PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(SIrp);
  352. POWER_STATE systemState = stack->Parameters.Power.State;
  353. DebugEnter();
  354. //
  355. // Read the D-IRP out of the S->D mapping array we captured in QueryCap's.
  356. // We can choose deeper sleep states than our mapping (with the appropriate
  357. // caveats if we have children), but we can never choose lighter ones, as
  358. // what hardware stays on in a given S-state is a function of the
  359. // motherboard wiring.
  360. //
  361. // Also note that if a driver rounds down it's D-state, it must ensure that
  362. // such a state is supported. A driver can do this by examining the
  363. // D1Supported? and D2Supported? flags (Win2k), or by examining the entire
  364. // S->D state mapping (Win98).
  365. //
  366. state.DeviceState = fdoData->DeviceCaps.DeviceState[systemState.SystemState];
  367. powerContext = (POWER_COMPLETION_CONTEXT*)
  368. ExAllocatePoolWithTag(NonPagedPool,
  369. sizeof(POWER_COMPLETION_CONTEXT),
  370. PROCESSOR_POOL_TAG);
  371. if (!powerContext) {
  372. status = STATUS_INSUFFICIENT_RESOURCES;
  373. } else {
  374. powerContext->DeviceObject = DeviceObject;
  375. powerContext->SIrp = SIrp;
  376. //
  377. // Note: Win2k's PoRequestPowerIrp can take an FDO,
  378. // but Win9x's requires the PDO.
  379. //
  380. status = PoRequestPowerIrp(fdoData->UnderlyingPDO,
  381. stack->MinorFunction,
  382. state, OnPowerRequestComplete,
  383. powerContext, NULL);
  384. }
  385. if (!NT_SUCCESS(status)) {
  386. if (powerContext) {
  387. ExFreePool(powerContext);
  388. }
  389. PoStartNextPowerIrp(SIrp);
  390. SIrp->IoStatus.Status = status;
  391. IoCompleteRequest(SIrp, IO_NO_INCREMENT);
  392. ProcessorIoDecrement(fdoData);
  393. }
  394. }
  395. VOID
  396. OnPowerRequestComplete(
  397. PDEVICE_OBJECT DeviceObject,
  398. UCHAR MinorFunction,
  399. POWER_STATE state,
  400. POWER_COMPLETION_CONTEXT* PowerContext,
  401. PIO_STATUS_BLOCK IoStatus
  402. )
  403. /*++
  404. Routine Description:
  405. Completion routine for D-IRP.
  406. Arguments:
  407. Return Value:
  408. --*/
  409. {
  410. PFDO_DATA fdoData = (PFDO_DATA) PowerContext->DeviceObject->DeviceExtension;
  411. PIRP sIrp = PowerContext->SIrp;
  412. DebugEnter();
  413. //
  414. // Here we copy the D-IRP status into the S-IRP
  415. //
  416. sIrp->IoStatus.Status = IoStatus->Status;
  417. //
  418. // Release the IRP
  419. //
  420. PoStartNextPowerIrp(sIrp);
  421. IoCompleteRequest(sIrp, IO_NO_INCREMENT);
  422. //
  423. // Cleanup
  424. //
  425. ExFreePool(PowerContext);
  426. ProcessorIoDecrement(fdoData);
  427. }
  428. NTSTATUS
  429. HandleDeviceQueryPower(
  430. PDEVICE_OBJECT DeviceObject,
  431. PIRP Irp
  432. )
  433. /*++
  434. Routine Description:
  435. Handles IRP_MN_QUERY_POWER for D-IRP
  436. Arguments:
  437. DeviceObject - pointer to a device object.
  438. Irp - pointer to an I/O Request Packet.
  439. Return Value:
  440. NT status code
  441. --*/
  442. {
  443. PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
  444. PFDO_DATA fdoData = (PFDO_DATA) DeviceObject->DeviceExtension;
  445. DEVICE_POWER_STATE deviceState = stack->Parameters.Power.State.DeviceState;
  446. NTSTATUS status;
  447. DebugEnter();
  448. //
  449. // Here we check to see if it's OK for our hardware to be suspended. Note
  450. // that our driver may have requests that would cause us to fail this
  451. // check. If so, we need to begin queuing requests after succeeding this
  452. // call (otherwise we may succeed such an IRP *after* we've said we can
  453. // power down).
  454. //
  455. // Note - we may be at DISPATCH_LEVEL here. As such the below code assumes
  456. // all I/O is handled at DISPATCH_LEVEL under a spinlock
  457. // (IoStartNextPacket style), or that this function cannot fail. If
  458. // such operations are to be handled at PASSIVE_LEVEL (meaning we
  459. // need to block on an *event* here), then this code should mark the
  460. // Irp pending (via IoMarkIrpPending), queue a workitem, and return
  461. // STATUS_PENDING.
  462. //
  463. if (deviceState == PowerDeviceD0) {
  464. //
  465. // Note - this driver does not queue IRPs if the S-to-D state mapping
  466. // specifies that the device will remain in D0 during standby.
  467. // For some devices, this could be a problem. For instance, if
  468. // an audio card where in a machine where S1->D0, it not want to
  469. // stay "active" during standby (could be noisy).
  470. //
  471. // Ideally, a driver would be able to use the ShutdownType field
  472. // in the D-IRP to distinguish these cases. Unfortunately, this
  473. // field cannot be trusted for D0 IRPs. A driver can get the same
  474. // information however by maintaining a pointer to the current
  475. // S-IRP in its device extension. Of course, such a driver must
  476. // be very very careful if it also does idle detection (which is
  477. // not shown here).
  478. //
  479. status = STATUS_SUCCESS;
  480. } else {
  481. status = HoldIoRequests(DeviceObject, Irp, IRP_NEEDS_FORWARDING);
  482. if(STATUS_PENDING == status)
  483. {
  484. return status;
  485. }
  486. }
  487. status = FinishDevicePowerIrp(DeviceObject, Irp, IRP_NEEDS_FORWARDING, status);
  488. return status;
  489. }
  490. NTSTATUS
  491. HandleDeviceSetPower(
  492. IN PDEVICE_OBJECT DeviceObject,
  493. IN PIRP Irp
  494. )
  495. /*++
  496. Routine Description:
  497. Handles IRP_MN_SET_POWER for D-IRP
  498. Arguments:
  499. DeviceObject - pointer to a device object.
  500. Irp - pointer to an I/O Request Packet.
  501. Return Value:
  502. NT status code
  503. --*/
  504. {
  505. PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
  506. POWER_STATE_TYPE type = stack->Parameters.Power.Type;
  507. POWER_STATE state = stack->Parameters.Power.State;
  508. NTSTATUS status;
  509. PFDO_DATA fdoData = (PFDO_DATA) DeviceObject->DeviceExtension;
  510. DebugEnter();
  511. if (state.DeviceState < fdoData->DevicePowerState) { // adding power
  512. IoCopyCurrentIrpStackLocationToNext(Irp);
  513. IoSetCompletionRoutine(Irp,
  514. (PIO_COMPLETION_ROUTINE) OnFinishDevicePowerUp,
  515. NULL, TRUE, TRUE, TRUE);
  516. PoCallDriver(fdoData->NextLowerDriver, Irp);
  517. return STATUS_PENDING;
  518. } else {
  519. //
  520. // We are here if we are entering a deeper sleep or entering a state
  521. // we are already in.
  522. //
  523. // As non-D0 IRPs are not alike (some may be for hibernate, shutdown,
  524. // or sleeping actions), we present these to our state machine.
  525. //
  526. // All D0 IRPs are alike though, and we don't want to touch our hardware
  527. // on a D0->D0 transition. However, we must still present them to our
  528. // state machine in case we succeeded a Query-D call (which may begin
  529. // queueing future requests) and the system has sent an S0 IRP to cancel
  530. // that preceeding query.
  531. //
  532. status = BeginSetDevicePowerState(DeviceObject, Irp, IRP_NEEDS_FORWARDING);
  533. return status;
  534. }
  535. }
  536. NTSTATUS
  537. OnFinishDevicePowerUp(
  538. IN PDEVICE_OBJECT DeviceObject,
  539. IN PIRP Irp,
  540. IN PVOID NotUsed
  541. )
  542. /*++
  543. Routine Description:
  544. The completion routine for Power Up D-IRP.
  545. Arguments:
  546. DeviceObject - pointer to a device object.
  547. Irp - pointer to an I/O Request Packet.
  548. Not used - context pointer
  549. Return Value:
  550. NT status code
  551. --*/
  552. {
  553. PFDO_DATA fdoData = (PFDO_DATA) DeviceObject->DeviceExtension;
  554. NTSTATUS status = Irp->IoStatus.Status;
  555. PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
  556. POWER_STATE_TYPE type = stack->Parameters.Power.Type;
  557. DebugEnter();
  558. if (Irp->PendingReturned) {
  559. IoMarkIrpPending(Irp);
  560. }
  561. if (!NT_SUCCESS(status)) {
  562. PoStartNextPowerIrp(Irp);
  563. ProcessorIoDecrement(fdoData);
  564. return STATUS_SUCCESS;
  565. }
  566. ASSERT(stack->MajorFunction == IRP_MJ_POWER);
  567. ASSERT(stack->MinorFunction == IRP_MN_SET_POWER);
  568. BeginSetDevicePowerState(DeviceObject, Irp, IRP_ALREADY_FORWARDED);
  569. return STATUS_MORE_PROCESSING_REQUIRED;
  570. }
  571. NTSTATUS
  572. BeginSetDevicePowerState(
  573. IN PDEVICE_OBJECT DeviceObject,
  574. IN PIRP Irp,
  575. IN IRP_DIRECTION Direction
  576. )
  577. /*++
  578. Routine Description:
  579. This routine performs the actual power changes to the device.
  580. Arguments:
  581. DeviceObject - pointer to a device object.
  582. Irp - pointer to an D-IRP.
  583. Direction - Whether to forward the D-IRP down or not.
  584. This depends on whether the system is powering
  585. up or down.
  586. Return Value:
  587. NT status code
  588. --*/
  589. {
  590. PFDO_DATA fdoData = (PFDO_DATA) DeviceObject->DeviceExtension;
  591. PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
  592. POWER_ACTION newDeviceAction;
  593. DEVICE_POWER_STATE newDeviceState, oldDeviceState;
  594. POWER_STATE newState;
  595. NTSTATUS status = STATUS_SUCCESS;
  596. DebugEnter();
  597. //
  598. // Note - Here we may be at DISPATCH_LEVEL. The below code assumes all I/O
  599. // is handled at DISPATCH_LEVEL under a spinlock (IoStartNextPacket
  600. // style). If such operations are to be handled at PASSIVE_LEVEL then
  601. // this code should queue a workitem if called at DISPATCH_LEVEL.
  602. //
  603. // Also note that we'd want to mark the IRP appropriately (via
  604. // IoMarkIrpPending) and we'd want to return STATUS_PENDING. As this
  605. // example does things synchronously, it is enough for us to return
  606. // the result of FinishSetDevicePowerState.
  607. //
  608. //
  609. // Update our state.
  610. //
  611. newState = stack->Parameters.Power.State;
  612. newDeviceState = newState.DeviceState;
  613. oldDeviceState = fdoData->DevicePowerState;
  614. fdoData->DevicePowerState = newDeviceState;
  615. DebugPrint((TRACE, "BeginSetDevicePowerState: Device State = %s\n",
  616. DbgDevicePowerString(fdoData->DevicePowerState)));
  617. if (newDeviceState > PowerDeviceD0) {
  618. //
  619. // We are here if our hardware is about to be turned off. HoldRequests
  620. // queues a workitem and returns immediately with STATUS_PENDING.
  621. //
  622. status = HoldIoRequests(DeviceObject, Irp, Direction);
  623. if(STATUS_PENDING == status)
  624. {
  625. return status;
  626. }
  627. }
  628. newDeviceAction = stack->Parameters.Power.ShutdownType;
  629. if (newDeviceState > oldDeviceState) {
  630. //
  631. // We are entering a deeper sleep state. Save away the appropriate
  632. // state and update our hardware. Note that this particular driver does
  633. // not care to distinguish Hibernates from shutdowns or standbys. If we
  634. // did the logic would also have to examine newDeviceAction.
  635. //
  636. PoSetPowerState(DeviceObject, DevicePowerState, newState);
  637. } else if (newDeviceState < oldDeviceState) {
  638. //
  639. // We are entering a lighter sleep state. Restore the appropriate amount
  640. // of state to our hardware.
  641. //
  642. PoSetPowerState(DeviceObject, DevicePowerState, newState);
  643. }
  644. if (newDeviceState == PowerDeviceD0) {
  645. //
  646. // Our hardware is now on again. Here we empty our existing queue of
  647. // requests and let in new ones. Note that if this is a D0->D0 (ie
  648. // no change) we will unblock our queue, which may have been blocked
  649. // processing our Query-D IRP.
  650. //
  651. fdoData->QueueState = AllowRequests;
  652. ProcessorProcessQueuedRequests(fdoData);
  653. status = STATUS_SUCCESS;
  654. }
  655. return FinishDevicePowerIrp(
  656. DeviceObject,
  657. Irp,
  658. Direction,
  659. status
  660. );
  661. }
  662. NTSTATUS
  663. FinishDevicePowerIrp(
  664. IN PDEVICE_OBJECT DeviceObject,
  665. IN PIRP Irp,
  666. IN IRP_DIRECTION Direction,
  667. IN NTSTATUS Result
  668. )
  669. /*++
  670. Routine Description:
  671. This is the final step in D-IRP handling.
  672. Arguments:
  673. DeviceObject - pointer to a device object.
  674. Irp - pointer to an D-IRP.
  675. Direction - Whether to forward the D-IRP down or not.
  676. This depends on whether the system is powering
  677. up or down.
  678. Result -
  679. Return Value:
  680. NT status code
  681. --*/
  682. {
  683. NTSTATUS status;
  684. PFDO_DATA fdoData = (PFDO_DATA) DeviceObject->DeviceExtension;
  685. DebugEnter();
  686. if (Direction == IRP_ALREADY_FORWARDED || (!NT_SUCCESS(Result))) {
  687. //
  688. // In either of these cases it is now time to complete the IRP.
  689. //
  690. PoStartNextPowerIrp(Irp);
  691. Irp->IoStatus.Status = Result;
  692. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  693. ProcessorIoDecrement(fdoData);
  694. return Result;
  695. }
  696. //
  697. // Here we update our result. Note that ProcessorDefaultPowerHandler calls
  698. // PoStartNextPowerIrp for us.
  699. //
  700. Irp->IoStatus.Status = Result;
  701. status = ProcessorDefaultPowerHandler(DeviceObject, Irp);
  702. ProcessorIoDecrement(fdoData);
  703. return status;
  704. }
  705. NTSTATUS
  706. HoldIoRequests(
  707. IN PDEVICE_OBJECT DeviceObject,
  708. IN PIRP Irp,
  709. IN IRP_DIRECTION Direction
  710. )
  711. /*++
  712. Routine Description:
  713. This routine sets queue state and queues an item to
  714. HoldIoRequestsWorkerRoutine.
  715. Arguments:
  716. Return Value:
  717. NT status code
  718. --*/
  719. {
  720. PIO_WORKITEM item;
  721. PWORKER_THREAD_CONTEXT context;
  722. NTSTATUS status;
  723. PFDO_DATA fdoData;
  724. DebugEnter();
  725. fdoData = (PFDO_DATA) DeviceObject->DeviceExtension;
  726. fdoData->QueueState = HoldRequests;
  727. //
  728. // We must wait for the pending I/Os to finish
  729. // before powering down the device. But we can't wait
  730. // while handling a power IRP because it can deadlock
  731. // the system. So let us queue a worker callback
  732. // item to do the wait and complete the irp.
  733. //
  734. context = ExAllocatePoolWithTag(PagedPool,
  735. sizeof(WORKER_THREAD_CONTEXT),
  736. PROCESSOR_POOL_TAG);
  737. if(context)
  738. {
  739. item = IoAllocateWorkItem(DeviceObject);
  740. context->Irp = Irp;
  741. context->DeviceObject= DeviceObject;
  742. context->IrpDirection = Direction;
  743. context->WorkItem = item;
  744. if (item) {
  745. IoMarkIrpPending(Irp);
  746. IoQueueWorkItem (item,
  747. HoldIoRequestsWorkerRoutine,
  748. DelayedWorkQueue,
  749. context);
  750. status = STATUS_PENDING;
  751. }
  752. else
  753. {
  754. ExFreePool(context);
  755. status = STATUS_INSUFFICIENT_RESOURCES;
  756. }
  757. }
  758. else
  759. status = STATUS_INSUFFICIENT_RESOURCES;
  760. return status;
  761. }
  762. VOID
  763. HoldIoRequestsWorkerRoutine(
  764. IN PDEVICE_OBJECT DeviceObject,
  765. IN PVOID Context
  766. )
  767. /*++
  768. Routine Description:
  769. This routine waits for the I/O in progress to finish and
  770. power downs the device.
  771. Arguments:
  772. Return Value:
  773. --*/
  774. {
  775. PFDO_DATA fdoData;
  776. PWORKER_THREAD_CONTEXT context = (PWORKER_THREAD_CONTEXT)Context;
  777. DebugEnter();
  778. fdoData = (PFDO_DATA) DeviceObject->DeviceExtension;
  779. DebugPrint((TRACE, "Waiting for pending requests to complete\n"));
  780. //
  781. // Wait for the I/O in progress to be finish.
  782. // The Stop event gets set when the counter drops
  783. // to Zero. Since our power handler routines incremented
  784. // the counter twice - once for the S-IRP and once for the
  785. // D-IRP - we must call the decrement function twice.
  786. //
  787. ProcessorIoDecrement(fdoData); // one
  788. ProcessorIoDecrement(fdoData);
  789. KeWaitForSingleObject(
  790. &fdoData->StopEvent,
  791. Executive, // Waiting for reason of a driver
  792. KernelMode, // Waiting in kernel mode
  793. FALSE, // No allert
  794. NULL); // No timeout
  795. //
  796. // Increment the counter back to take into account the S-IRP and D-IRP
  797. // currently in progress.
  798. //
  799. ProcessorIoIncrement (fdoData);
  800. ProcessorIoIncrement (fdoData);
  801. FinishDevicePowerIrp(
  802. context->DeviceObject,
  803. context->Irp,
  804. context->IrpDirection,
  805. STATUS_SUCCESS
  806. );
  807. //
  808. // Cleanup before exiting from the worker thread.
  809. //
  810. IoFreeWorkItem(context->WorkItem);
  811. ExFreePool((PVOID)context);
  812. }
  813. VOID
  814. ProcessorPowerStateCallback(
  815. IN PVOID CallbackContext,
  816. IN PVOID Argument1,
  817. IN PVOID Argument2
  818. )
  819. /*++
  820. Routine Description:
  821. Arguments:
  822. Return Value:
  823. --*/
  824. {
  825. ULONG_PTR action = (ULONG_PTR)Argument1;
  826. ULONG_PTR state = (ULONG_PTR)Argument2;
  827. DebugEnter();
  828. DisplayPowerStateInfo(action, state);
  829. if (action == PO_CB_SYSTEM_STATE_LOCK) {
  830. switch (state) {
  831. case 0:
  832. //
  833. // Lock down everything in the PAGELK code section.
  834. //
  835. ProcessorSleepPageLock = MmLockPagableCodeSection((PVOID)ProcessorDispatchPower);
  836. break;
  837. case 1:
  838. //
  839. // unlock it all
  840. //
  841. MmUnlockPagableImageSection(ProcessorSleepPageLock);
  842. break;
  843. default:
  844. DebugPrint((TRACE, "Unknown callback operation.\n"));
  845. }
  846. } else if (action == PO_CB_AC_STATUS) {
  847. //
  848. // AC <-> DC Transition has occurred, call Notify routine.
  849. // State == TRUE if on AC, else FALSE.
  850. //
  851. // toddcar - 02/14/01 - ISSUE:
  852. // should we call this sync or async?
  853. //
  854. if (AcDcTransitionNotifyHandler.Handler) {
  855. AcDcTransitionNotifyHandler.Handler(AcDcTransitionNotifyHandler.Context,
  856. (BOOLEAN) state);
  857. }
  858. }
  859. return;
  860. }
  861. NTSTATUS
  862. RegisterAcDcTransitionNotifyHandler (
  863. IN PAC_DC_NOTIFY_HANDLER NewHandler,
  864. IN PVOID Context
  865. )
  866. /*++
  867. Routine Description:
  868. Arguments:
  869. Return Value:
  870. --*/
  871. {
  872. //
  873. // Notify handler can only be registered once.
  874. //
  875. if (AcDcTransitionNotifyHandler.Handler && NewHandler) {
  876. return STATUS_INVALID_PARAMETER;
  877. }
  878. //
  879. // Set new handler
  880. //
  881. AcDcTransitionNotifyHandler.Handler = NewHandler;
  882. AcDcTransitionNotifyHandler.Context = Context;
  883. return STATUS_SUCCESS;
  884. }