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.

734 lines
19 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. power.c
  5. Abstract:
  6. This file contains the support for power management
  7. Environment:
  8. Kernel Mode Driver.
  9. Notes:
  10. Nothing in here or in routines referenced from here should be pageable.
  11. Revision History:
  12. --*/
  13. #include "busp.h"
  14. #include "pnpisa.h"
  15. #include <initguid.h>
  16. #include <wdmguid.h>
  17. #include "halpnpp.h"
  18. NTSTATUS
  19. PiDispatchPower(
  20. IN PDEVICE_OBJECT DeviceObject,
  21. IN OUT PIRP Irp
  22. );
  23. NTSTATUS
  24. PiDispatchPowerFdo(
  25. IN PDEVICE_OBJECT DeviceObject,
  26. IN OUT PIRP Irp
  27. );
  28. NTSTATUS
  29. PiDispatchPowerPdo(
  30. IN PDEVICE_OBJECT DeviceObject,
  31. IN OUT PIRP Irp
  32. );
  33. NTSTATUS
  34. PipPassPowerIrpFdo(
  35. PDEVICE_OBJECT DeviceObject,
  36. PIRP Irp
  37. );
  38. NTSTATUS
  39. PipPowerIrpNotSupportedPdo(
  40. PDEVICE_OBJECT DeviceObject,
  41. PIRP Irp
  42. );
  43. NTSTATUS
  44. PipQueryPowerStatePdo (
  45. IN PDEVICE_OBJECT DeviceObject,
  46. IN OUT PIRP Irp
  47. );
  48. NTSTATUS
  49. PipSetPowerStatePdo (
  50. IN PDEVICE_OBJECT DeviceObject,
  51. IN OUT PIRP Irp
  52. );
  53. NTSTATUS
  54. PipSetQueryPowerStateFdo (
  55. IN PDEVICE_OBJECT DeviceObject,
  56. IN OUT PIRP Irp
  57. );
  58. NTSTATUS
  59. PipRequestPowerUpCompletionRoutinePdo (
  60. IN PDEVICE_OBJECT DeviceObject,
  61. IN UCHAR MinorFunction,
  62. IN POWER_STATE PowerState,
  63. IN PVOID Context,
  64. IN PIO_STATUS_BLOCK IoStatus
  65. );
  66. NTSTATUS
  67. FdoContingentPowerCompletionRoutine (
  68. IN PDEVICE_OBJECT DeviceObject,
  69. IN UCHAR MinorFunction,
  70. IN POWER_STATE PowerState,
  71. IN PVOID Context,
  72. IN PIO_STATUS_BLOCK IoStatus
  73. );
  74. const PUCHAR SystemPowerStateStrings[] = {
  75. "Unspecified",
  76. "Working",
  77. "Sleeping1",
  78. "Sleeping2",
  79. "Sleeping3",
  80. "Hibernate",
  81. "Shutdown"
  82. };
  83. const PUCHAR DevicePowerStateStrings[] = {
  84. "Unspecified",
  85. "D0",
  86. "D1",
  87. "D2",
  88. "D3"
  89. };
  90. const PPI_DISPATCH PiPowerDispatchTableFdo[] =
  91. {
  92. PipPassPowerIrpFdo,
  93. PipPassPowerIrpFdo,
  94. PipSetQueryPowerStateFdo,
  95. PipSetQueryPowerStateFdo,
  96. };
  97. #if ISOLATE_CARDS
  98. const PPI_DISPATCH PiPowerDispatchTablePdo[] =
  99. {
  100. PipPowerIrpNotSupportedPdo,
  101. PipPowerIrpNotSupportedPdo,
  102. PipSetPowerStatePdo,
  103. PipQueryPowerStatePdo,
  104. };
  105. #endif
  106. VOID
  107. PipDumpPowerIrpLocation(
  108. PIO_STACK_LOCATION IrpSp
  109. )
  110. {
  111. DebugPrintContinue((
  112. DEBUG_POWER,
  113. "%s %d\n",
  114. (IrpSp->Parameters.Power.Type == DevicePowerState) ?
  115. DevicePowerStateStrings[IrpSp->Parameters.Power.State.DeviceState] : SystemPowerStateStrings[IrpSp->Parameters.Power.State.SystemState],
  116. IrpSp->Parameters.Power.ShutdownType));
  117. }
  118. NTSTATUS
  119. PiDispatchPower(
  120. IN PDEVICE_OBJECT DeviceObject,
  121. IN OUT PIRP Irp
  122. )
  123. /*++
  124. Routine Description:
  125. This routine handles all the IRP_MJ_POWER IRPs.
  126. Arguments:
  127. DeviceObject - Pointer to the device object for which this IRP applies.
  128. Irp - Pointer to the IRP_MJ_PNP_POWER IRP to dispatch.
  129. Return Value:
  130. NT status.
  131. --*/
  132. {
  133. PIO_STACK_LOCATION irpSp;
  134. NTSTATUS status = STATUS_SUCCESS;
  135. PPI_BUS_EXTENSION busExtension;
  136. //
  137. // Make sure this is a valid device object.
  138. //
  139. busExtension = DeviceObject->DeviceExtension;
  140. #if !ISOLATE_CARDS
  141. return PiDispatchPowerFdo(DeviceObject, Irp);
  142. #else
  143. if (busExtension->Flags & DF_BUS) {
  144. return PiDispatchPowerFdo(DeviceObject, Irp);
  145. } else {
  146. return PiDispatchPowerPdo(DeviceObject, Irp);
  147. }
  148. #endif
  149. }
  150. #if ISOLATE_CARDS
  151. NTSTATUS
  152. PipPowerIrpNotSupportedPdo(
  153. PDEVICE_OBJECT DeviceObject,
  154. PIRP Irp
  155. )
  156. {
  157. PIO_STACK_LOCATION irpSp;
  158. irpSp = IoGetCurrentIrpStackLocation(Irp);
  159. PoStartNextPowerIrp(Irp);
  160. DebugPrint((DEBUG_POWER,
  161. "Completing unsupported power irp %x for PDO %x\n",
  162. irpSp->MinorFunction,
  163. DeviceObject
  164. ));
  165. PipCompleteRequest(Irp, STATUS_NOT_SUPPORTED, NULL);
  166. return STATUS_NOT_SUPPORTED;
  167. }
  168. NTSTATUS
  169. PiDispatchPowerPdo(
  170. IN PDEVICE_OBJECT DeviceObject,
  171. IN OUT PIRP Irp
  172. )
  173. /*++
  174. Routine Description:
  175. This routine handles all the IRP_MJ_POWER IRPs.
  176. Arguments:
  177. DeviceObject - Pointer to the device object for which this IRP applies.
  178. Irp - Pointer to the IRP_MJ_PNP_POWER IRP to dispatch.
  179. Return Value:
  180. NT status.
  181. --*/
  182. {
  183. PIO_STACK_LOCATION irpSp;
  184. NTSTATUS status = STATUS_SUCCESS;
  185. PDEVICE_INFORMATION deviceExtension;
  186. //
  187. // Make sure this is a valid device object.
  188. //
  189. deviceExtension = DeviceObject->DeviceExtension;
  190. if (deviceExtension->Flags & DF_DELETED) {
  191. status = STATUS_NO_SUCH_DEVICE;
  192. PoStartNextPowerIrp(Irp);
  193. PipCompleteRequest(Irp, status, NULL);
  194. return status;
  195. }
  196. //
  197. // Get a pointer to our stack location and take appropriate action based
  198. // on the minor function.
  199. //
  200. irpSp = IoGetCurrentIrpStackLocation(Irp);
  201. if (irpSp->MinorFunction > IRP_MN_PO_MAXIMUM_FUNCTION) {
  202. status = PipPowerIrpNotSupportedPdo(DeviceObject, Irp);
  203. } else {
  204. status = PiPowerDispatchTablePdo[irpSp->MinorFunction](DeviceObject, Irp);
  205. }
  206. return status;
  207. }
  208. NTSTATUS
  209. PipQueryPowerStatePdo (
  210. IN PDEVICE_OBJECT DeviceObject,
  211. IN OUT PIRP Irp
  212. )
  213. /*++
  214. Routine Description:
  215. This routine handles the Query_Power irp for the PDO .
  216. Arguments:
  217. DeviceObject - Pointer to the device object for which this IRP applies.
  218. Irp - Pointer to the IRP_MJ_PNP_POWER IRP to dispatch.
  219. Return Value:
  220. NT status.
  221. --*/
  222. {
  223. DEVICE_POWER_STATE targetState;
  224. NTSTATUS status;
  225. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
  226. DebugPrint((DEBUG_POWER, "QueryPower on PDO %x: ", DeviceObject));
  227. PipDumpPowerIrpLocation(irpSp);
  228. if (irpSp->Parameters.Power.Type == DevicePowerState) {
  229. targetState=irpSp->Parameters.Power.State.DeviceState;
  230. ASSERT ((targetState == PowerDeviceD0) ||
  231. (targetState == PowerDeviceD3));
  232. if ((targetState == PowerDeviceD0) ||
  233. (targetState == PowerDeviceD3) ) {
  234. status=Irp->IoStatus.Status = STATUS_SUCCESS;
  235. } else {
  236. status=Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  237. }
  238. } else {
  239. //
  240. // Just succeed S irps
  241. //
  242. status=Irp->IoStatus.Status = STATUS_SUCCESS;
  243. }
  244. PoStartNextPowerIrp (Irp);
  245. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  246. DebugPrint((DEBUG_POWER, "QueryPower on PDO %x: returned %x\n", DeviceObject, status));
  247. return status;
  248. }
  249. NTSTATUS
  250. PipSetPowerStatePdo (
  251. IN PDEVICE_OBJECT DeviceObject,
  252. IN OUT PIRP Irp
  253. )
  254. /*++
  255. Routine Description:
  256. This routine handles SET_POWER_IRP for the IsaPnp device (i.e. PDO)
  257. It sets the devices power state to the power state type as indicated. In
  258. the case of a device state change which is transitioning a device out of
  259. the PowerDevice0 state, we need call PoSetPowerState prior to leaving the
  260. PowerDeviceD0. In the case if a device state change which is transitioning
  261. a device into the PowerDeviceD0 state, we call PoSetPowerState after the
  262. device is successfully put into the PowerDeviceD0 state.
  263. Arguments:
  264. DeviceObject - Pointer to the device object for which this IRP applies.
  265. Irp - Pointer to the IRP_MJ_PNP_POWER IRP to dispatch.
  266. Return Value:
  267. NT status.
  268. --*/
  269. {
  270. PDEVICE_INFORMATION pdoExtension;
  271. NTSTATUS status;
  272. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
  273. DEVICE_POWER_STATE targetState=irpSp->Parameters.Power.State.DeviceState;
  274. POWER_STATE newState;
  275. DebugPrint((DEBUG_POWER, "SetPower on PDO %x: ", DeviceObject));
  276. PipDumpPowerIrpLocation(irpSp);
  277. pdoExtension = PipReferenceDeviceInformation(DeviceObject, FALSE);
  278. if (pdoExtension == NULL) {
  279. status = STATUS_NO_SUCH_DEVICE;
  280. } else if (pdoExtension->Flags & DF_NOT_FUNCTIONING) {
  281. status = STATUS_NO_SUCH_DEVICE;
  282. PipDereferenceDeviceInformation(pdoExtension, FALSE);
  283. } else {
  284. if (irpSp->Parameters.Power.Type == DevicePowerState) {
  285. // * On transition from D0 to D0, we do nothing.
  286. //
  287. // * On transition to D3, we'll deactivate the card.
  288. //
  289. // * On transition from D3->D0 we'll refresh the resources
  290. // and activate the card.
  291. //
  292. if ((targetState == PowerDeviceD0) &&
  293. (pdoExtension->DevicePowerState == PowerDeviceD0)) {
  294. // Do not try to power device back up if this is a D0->D0
  295. // transition. The device is already powered.
  296. DebugPrint((DEBUG_POWER,
  297. "PDO %x D0 -> D0 Transition ignored\n", DeviceObject));
  298. } else if ((pdoExtension->DevicePowerState == PowerDeviceD0) &&
  299. pdoExtension->CrashDump) {
  300. DebugPrint((DEBUG_POWER,
  301. "PDO %x D0 -> ?? Transition ignored, crash file\n",
  302. DeviceObject));
  303. } else if (targetState > PowerDeviceD0) {
  304. targetState = PowerDeviceD3;
  305. DebugPrint((DEBUG_POWER,
  306. "Powering down PDO %x CSN %d/LDN %d\n",
  307. DeviceObject,
  308. pdoExtension->CardInformation->CardSelectNumber,
  309. pdoExtension->LogicalDeviceNumber
  310. ));
  311. if ((pdoExtension->Flags & (DF_ACTIVATED | DF_READ_DATA_PORT)) == DF_ACTIVATED) {
  312. if (!(PipRDPNode->Flags & (DF_STOPPED|DF_REMOVED|DF_SURPRISE_REMOVED))) {
  313. PipWakeAndSelectDevice(
  314. (UCHAR) pdoExtension->CardInformation->CardSelectNumber,
  315. (UCHAR) pdoExtension->LogicalDeviceNumber);
  316. PipDeactivateDevice();
  317. PipWaitForKey();
  318. } else {
  319. targetState = PowerDeviceD0;
  320. }
  321. }
  322. } else {
  323. if ((pdoExtension->Flags & (DF_ACTIVATED | DF_READ_DATA_PORT)) == DF_ACTIVATED) {
  324. DebugPrint((DEBUG_POWER,
  325. "Powering up PDO %x CSN %d/LDN %d\n",
  326. DeviceObject,
  327. pdoExtension->CardInformation->CardSelectNumber,
  328. pdoExtension->LogicalDeviceNumber
  329. ));
  330. if (!(PipRDPNode->Flags & (DF_STOPPED|DF_REMOVED|DF_SURPRISE_REMOVED))) {
  331. PipWakeAndSelectDevice(
  332. (UCHAR) pdoExtension->CardInformation->CardSelectNumber,
  333. (UCHAR) pdoExtension->LogicalDeviceNumber);
  334. status = PipSetDeviceResources(
  335. pdoExtension,
  336. pdoExtension->AllocatedResources);
  337. if (NT_SUCCESS(status)) {
  338. PipActivateDevice();
  339. }
  340. PipWaitForKey();
  341. } else {
  342. targetState = PowerDeviceD3;
  343. }
  344. }
  345. }
  346. newState.DeviceState = targetState;
  347. PoSetPowerState(DeviceObject, DevicePowerState, newState);
  348. pdoExtension->DevicePowerState = targetState;
  349. }
  350. status = STATUS_SUCCESS;
  351. PipDereferenceDeviceInformation(pdoExtension, FALSE);
  352. }
  353. Irp->IoStatus.Status = status;
  354. PoStartNextPowerIrp (Irp);
  355. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  356. DebugPrint((DEBUG_POWER, "SetPower on PDO %x: returned %x\n", DeviceObject, status));
  357. return status;
  358. }
  359. #endif
  360. NTSTATUS
  361. PipPassPowerIrpFdo(
  362. PDEVICE_OBJECT DeviceObject,
  363. PIRP Irp
  364. )
  365. /*++
  366. Description:
  367. This function pass the power Irp to lower level driver.
  368. Arguments:
  369. DeviceObject - the Fdo
  370. Irp - the request
  371. Return:
  372. STATUS_PENDING
  373. --*/
  374. {
  375. NTSTATUS status;
  376. PPI_BUS_EXTENSION busExtension;
  377. PIO_STACK_LOCATION irpSp;
  378. PoStartNextPowerIrp(Irp);
  379. irpSp = IoGetCurrentIrpStackLocation(Irp);
  380. busExtension = (PPI_BUS_EXTENSION) DeviceObject->DeviceExtension;
  381. DebugPrint((DEBUG_POWER,
  382. "Passing down power irp %x for FDO %x to %x\n",
  383. irpSp->MinorFunction,
  384. DeviceObject,
  385. busExtension->AttachedDevice
  386. ));
  387. IoSkipCurrentIrpStackLocation(Irp);
  388. status = PoCallDriver(busExtension->AttachedDevice, Irp);
  389. DebugPrint((DEBUG_POWER,
  390. "Passed down power irp for FDO: returned %x\n",
  391. status));
  392. return status;
  393. }
  394. NTSTATUS
  395. PiDispatchPowerFdo(
  396. IN PDEVICE_OBJECT DeviceObject,
  397. IN OUT PIRP Irp
  398. )
  399. /*++
  400. Routine Description:
  401. This routine handles all the IRP_MJ_POWER IRPs.
  402. Arguments:
  403. DeviceObject - Pointer to the device object for which this IRP applies.
  404. Irp - Pointer to the IRP_MJ_PNP_POWER IRP to dispatch.
  405. Return Value:
  406. NT status.
  407. --*/
  408. {
  409. PIO_STACK_LOCATION irpSp;
  410. NTSTATUS status = STATUS_SUCCESS;
  411. PPI_BUS_EXTENSION busExtension;
  412. //
  413. // Make sure this is a valid device object.
  414. //
  415. busExtension = DeviceObject->DeviceExtension;
  416. if (busExtension->AttachedDevice == NULL) {
  417. status = STATUS_NO_SUCH_DEVICE;
  418. PoStartNextPowerIrp(Irp);
  419. PipCompleteRequest(Irp, status, NULL);
  420. return status;
  421. }
  422. //
  423. // Get a pointer to our stack location and take appropriate action based
  424. // on the minor function.
  425. //
  426. irpSp = IoGetCurrentIrpStackLocation(Irp);
  427. if (irpSp->MinorFunction > IRP_MN_PO_MAXIMUM_FUNCTION) {
  428. return PipPassPowerIrpFdo(DeviceObject, Irp);
  429. } else {
  430. status = PiPowerDispatchTableFdo[irpSp->MinorFunction](DeviceObject, Irp);
  431. }
  432. return status;
  433. }
  434. NTSTATUS
  435. PipSetQueryPowerStateFdo (
  436. IN PDEVICE_OBJECT DeviceObject,
  437. IN OUT PIRP Irp
  438. )
  439. /*++
  440. Routine Description:
  441. This routine handles QUERY_POWER or SET_POWER IRPs for the IsaPnp bus device
  442. (i.e. FDO). It sets the devices power state for the power state type as indicated.
  443. In the case of a device state change which is transitioning a device out of
  444. the PowerDevice0 state, we need call PoSetPowerState prior to leaving the
  445. PowerDeviceD0. In the case if a device state change which is transitioning
  446. a device into the PowerDeviceD0 state, we call PoSetPowerState after the
  447. device is successfully put into the PowerDeviceD0 state.
  448. Arguments:
  449. DeviceObject - Pointer to the device object for which this IRP applies.
  450. Irp - Pointer to the IRP_MJ_PNP_POWER IRP to dispatch.
  451. Return Value:
  452. NT status.
  453. --*/
  454. {
  455. PPI_BUS_EXTENSION fdoExtension;
  456. PIO_STACK_LOCATION irpSp;
  457. NTSTATUS status;
  458. fdoExtension = DeviceObject->DeviceExtension;
  459. irpSp = IoGetCurrentIrpStackLocation (Irp);
  460. DebugPrint((DEBUG_POWER, "%s on FDO %x: ",
  461. (irpSp->MinorFunction == IRP_MN_SET_POWER) ? "SetPower" :
  462. "QueryPower", DeviceObject));
  463. PipDumpPowerIrpLocation(irpSp);
  464. if (irpSp->Parameters.Power.Type == SystemPowerState) {
  465. POWER_STATE powerState;
  466. switch (irpSp->Parameters.Power.State.SystemState) {
  467. case PowerSystemWorking:
  468. //
  469. // Make sure the bus is on for these system states
  470. //
  471. powerState.DeviceState = PowerDeviceD0;
  472. break;
  473. case PowerSystemSleeping1:
  474. case PowerSystemHibernate:
  475. case PowerSystemShutdown:
  476. case PowerSystemSleeping2:
  477. case PowerSystemSleeping3:
  478. //
  479. // Going to sleep ... Power down
  480. //
  481. powerState.DeviceState = PowerDeviceD3;
  482. break;
  483. default:
  484. //
  485. // Unknown request - be safe power up
  486. //
  487. ASSERT (TRUE == FALSE);
  488. powerState.DeviceState = PowerDeviceD0;
  489. break;
  490. }
  491. DebugPrint((DEBUG_POWER, "request power irp to busdev %x, pending\n",
  492. fdoExtension->FunctionalBusDevice));
  493. IoMarkIrpPending(Irp);
  494. PoRequestPowerIrp (
  495. fdoExtension->FunctionalBusDevice,
  496. irpSp->MinorFunction,
  497. powerState,
  498. FdoContingentPowerCompletionRoutine,
  499. Irp,
  500. NULL
  501. );
  502. return STATUS_PENDING;
  503. }
  504. status = PipPassPowerIrpFdo(DeviceObject, Irp);
  505. DebugPrint((DEBUG_POWER, "SetPower(device) on FDO %x: returned %x\n", DeviceObject, status));
  506. return status;
  507. }
  508. NTSTATUS
  509. FdoContingentPowerCompletionRoutine (
  510. IN PDEVICE_OBJECT DeviceObject,
  511. IN UCHAR MinorFunction,
  512. IN POWER_STATE PowerState,
  513. IN PVOID Context,
  514. IN PIO_STATUS_BLOCK IoStatus
  515. )
  516. {
  517. PIRP irp = Context;
  518. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp);
  519. DebugPrint((DEBUG_POWER, "requested power irp completed to %x\n", DeviceObject));
  520. //
  521. // Propagate the status of the transient power IRP
  522. //
  523. irp->IoStatus.Status = IoStatus->Status;
  524. if (NT_SUCCESS(IoStatus->Status)) {
  525. PPI_BUS_EXTENSION fdoExtension;
  526. fdoExtension = DeviceObject->DeviceExtension;
  527. PoStartNextPowerIrp (irp);
  528. //
  529. // changing device power state call PoSetPowerState now.
  530. //
  531. if (MinorFunction == IRP_MN_SET_POWER) {
  532. SYSTEM_POWER_STATE OldSystemPowerState = fdoExtension->SystemPowerState;
  533. fdoExtension->SystemPowerState = irpSp->Parameters.Power.State.SystemState;
  534. fdoExtension->DevicePowerState = PowerState.DeviceState;
  535. PoSetPowerState (
  536. DeviceObject,
  537. DevicePowerState,
  538. PowerState
  539. );
  540. DebugPrint((DEBUG_POWER, "New FDO %x powerstate system %s/%s\n",
  541. DeviceObject,
  542. SystemPowerStateStrings[fdoExtension->SystemPowerState],
  543. DevicePowerStateStrings[fdoExtension->DevicePowerState]));
  544. #if ISOLATE_CARDS
  545. if ((OldSystemPowerState == PowerSystemHibernate) ||
  546. (OldSystemPowerState == PowerSystemSleeping3) ) {
  547. BOOLEAN needsRescan;
  548. PipReportStateChange(PiSWaitForKey);
  549. if ((fdoExtension->BusNumber == 0) && PipRDPNode &&
  550. (PipRDPNode->Flags & (DF_ACTIVATED|DF_PROCESSING_RDP|DF_QUERY_STOPPED)) == DF_ACTIVATED) {
  551. needsRescan = PipMinimalCheckBus(fdoExtension);
  552. if (needsRescan) {
  553. PipRDPNode->Flags |= DF_NEEDS_RESCAN;
  554. IoInvalidateDeviceRelations(
  555. fdoExtension->PhysicalBusDevice,
  556. BusRelations);
  557. }
  558. }
  559. }
  560. #endif
  561. }
  562. IoSkipCurrentIrpStackLocation (irp);
  563. PoCallDriver (fdoExtension->AttachedDevice, irp);
  564. } else {
  565. PoStartNextPowerIrp (irp);
  566. IoCompleteRequest(irp, IO_NO_INCREMENT);
  567. }
  568. return STATUS_SUCCESS;
  569. } // FdoContingentPowerCompletionRoutine