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.

1166 lines
28 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. misc.c
  5. Abstract:
  6. This module implements miscellaneous power management functions
  7. Author:
  8. Ken Reneris (kenr) 19-July-1994
  9. Revision History:
  10. --*/
  11. #include "pop.h"
  12. #ifdef ALLOC_PRAGMA
  13. #pragma alloc_text(PAGE,PoInitializeDeviceObject)
  14. #pragma alloc_text(PAGELK,PoRunDownDeviceObject)
  15. #pragma alloc_text(PAGE,PopCleanupPowerState)
  16. #pragma alloc_text(PAGE,PopChangeCapability)
  17. #pragma alloc_text(PAGE,PopExceptionFilter)
  18. #pragma alloc_text(PAGELK,PopSystemStateString)
  19. #pragma alloc_text(PAGE,PopOpenPowerKey)
  20. #pragma alloc_text(PAGE,PopInitializePowerPolicySimulate)
  21. #pragma alloc_text(PAGE,PopSaveHeuristics)
  22. #pragma alloc_text(PAGE,PoInvalidateDevicePowerRelations)
  23. #pragma alloc_text(PAGE,PoGetLightestSystemStateForEject)
  24. #pragma alloc_text(PAGE,PoGetDevicePowerState)
  25. #pragma alloc_text(PAGE, PopUnlockAfterSleepWorker)
  26. #if DBG
  27. #pragma alloc_text(PAGE, PopPowerActionString)
  28. #pragma alloc_text(PAGE, PopAssertPolicyLockOwned)
  29. #endif
  30. #endif
  31. //
  32. // TCP/IP checksum that we use if it is available
  33. //
  34. ULONG
  35. tcpxsum(
  36. IN ULONG cksum,
  37. IN PUCHAR buf,
  38. IN ULONG_PTR len
  39. );
  40. VOID
  41. PoInitializeDeviceObject (
  42. IN PDEVOBJ_EXTENSION DeviceObjectExtension
  43. )
  44. {
  45. //
  46. // default to unspecified power states, not Inrush, Pageable.
  47. //
  48. DeviceObjectExtension->PowerFlags = 0L;
  49. PopSetDoSystemPowerState(DeviceObjectExtension, PowerSystemUnspecified);
  50. PopSetDoDevicePowerState(DeviceObjectExtension, PowerDeviceUnspecified);
  51. DeviceObjectExtension->Dope = NULL;
  52. }
  53. VOID
  54. PoRunDownDeviceObject (
  55. IN PDEVICE_OBJECT DeviceObject
  56. )
  57. {
  58. KIRQL OldIrql;
  59. PDEVOBJ_EXTENSION doe;
  60. PDEVICE_OBJECT_POWER_EXTENSION pdope;
  61. ULONG D0Count;
  62. doe = (PDEVOBJ_EXTENSION) DeviceObject->DeviceObjectExtension;
  63. //
  64. // force off any idle counter that may be active
  65. //
  66. PoRegisterDeviceForIdleDetection(
  67. DeviceObject, 0, 0, PowerDeviceUnspecified
  68. );
  69. if (PopFindIrpByDeviceObject(DeviceObject, DevicePowerState) ||
  70. PopFindIrpByDeviceObject(DeviceObject, SystemPowerState))
  71. {
  72. PopInternalAddToDumpFile( NULL, 0, DeviceObject, NULL, NULL, NULL );
  73. KeBugCheckEx(
  74. DRIVER_POWER_STATE_FAILURE,
  75. DEVICE_DELETED_WITH_POWER_IRPS,
  76. 0x100,
  77. (ULONG_PTR) DeviceObject,
  78. 0 );
  79. }
  80. //
  81. // knock down notify structures attached to this DO.
  82. //
  83. PopRunDownSourceTargetList(DeviceObject);
  84. //
  85. // knock down the dope
  86. //
  87. pdope = doe->Dope;
  88. if (pdope) {
  89. ASSERT(ExPageLockHandle);
  90. MmLockPagableSectionByHandle(ExPageLockHandle);
  91. PopAcquireVolumeLock ();
  92. PopLockDopeGlobal(&OldIrql);
  93. if (pdope->Volume.Flink) {
  94. RemoveEntryList (&pdope->Volume);
  95. doe->Dope->Volume.Flink = NULL;
  96. doe->Dope->Volume.Blink = NULL;
  97. }
  98. doe->Dope = NULL;
  99. ExFreePool(pdope);
  100. PopUnlockDopeGlobal(OldIrql);
  101. PopReleaseVolumeLock ();
  102. MmUnlockPagableImageSection (ExPageLockHandle);
  103. }
  104. }
  105. VOID
  106. PopCleanupPowerState (
  107. IN OUT PUCHAR PowerState
  108. )
  109. /*++
  110. Routine Description:
  111. Used to cleanup the Thread->Tcb.PowerState or the Process->Pcb.PowerState
  112. during thread or process rundown
  113. Arguments:
  114. PowerState - Which power state to cleanup
  115. Return Value:
  116. None
  117. --*/
  118. {
  119. ULONG OldFlags;
  120. //
  121. // If power state is set, clean it up
  122. //
  123. if (*PowerState) {
  124. PopAcquirePolicyLock ();
  125. //
  126. // Get current settings and clear them
  127. //
  128. OldFlags = *PowerState | ES_CONTINUOUS;
  129. *PowerState = 0;
  130. //
  131. // Account for attribute settings which are being cleared
  132. //
  133. PopApplyAttributeState (ES_CONTINUOUS, OldFlags);
  134. //
  135. // Done
  136. //
  137. PopReleasePolicyLock (TRUE);
  138. }
  139. }
  140. VOID
  141. PoNotifySystemTimeSet (
  142. VOID
  143. )
  144. /*++
  145. Routine Description:
  146. Called by KE after a new system time has been set. Enqueues
  147. a notification to the proper system components that the time
  148. has been changed.
  149. Arguments:
  150. None
  151. Return Value:
  152. None
  153. --*/
  154. {
  155. KIRQL OldIrql;
  156. if (PopEventCallout) {
  157. KeRaiseIrql (DISPATCH_LEVEL, &OldIrql);
  158. ExNotifyCallback (ExCbSetSystemTime, NULL, NULL);
  159. PopGetPolicyWorker (PO_WORKER_TIME_CHANGE);
  160. PopCheckForWork (TRUE);
  161. KeLowerIrql (OldIrql);
  162. }
  163. }
  164. VOID
  165. PopChangeCapability (
  166. IN PBOOLEAN PresentFlag,
  167. IN BOOLEAN IsPresent
  168. )
  169. {
  170. //
  171. // If feature wasn't present before, it is now. Re-compute policies
  172. // as system capabilities changed
  173. //
  174. if (*PresentFlag != IsPresent) {
  175. *PresentFlag = IsPresent;
  176. PopResetCurrentPolicies ();
  177. PopSetNotificationWork (PO_NOTIFY_CAPABILITIES);
  178. }
  179. }
  180. #if DBG
  181. VOID
  182. PopAssertPolicyLockOwned(
  183. VOID
  184. )
  185. {
  186. PAGED_CODE();
  187. ASSERT (PopPolicyLockThread == KeGetCurrentThread());
  188. }
  189. #endif // DBG
  190. VOID
  191. FASTCALL
  192. PopInternalAddToDumpFile (
  193. IN OPTIONAL PVOID DataBlock,
  194. IN OPTIONAL ULONG DataBlockSize,
  195. IN OPTIONAL PDEVICE_OBJECT DeviceObject,
  196. IN OPTIONAL PDRIVER_OBJECT DriverObject,
  197. IN OPTIONAL PDEVOBJ_EXTENSION Doe,
  198. IN OPTIONAL PDEVICE_OBJECT_POWER_EXTENSION Dope
  199. )
  200. /*++
  201. Routine Description:
  202. Called just before bugchecking. This function will ensure that
  203. things we care about get into the dump file for later debugging.
  204. It should be noted that many of the parameters can be derived
  205. from each other. However, since we're about to bugcheck, we run
  206. a risk of double-faulting while we're chasing pointers. Therefore,
  207. we give the caller the option to override some of the pointers by
  208. sending us a pointer directly.
  209. Arguments:
  210. DataBlock - Generic block of memory to place into the dump file.
  211. DataBlockSize - Size of DataBlock (in bytes).
  212. DeviceObject - DEVICE_OBJECT to place into dump file.
  213. DriverObject - DRIVER_OBJECT to place into dump file.
  214. N.B. This overrides a value we may find in DeviceObject->DriverObject
  215. Doe - DEVOBJ_EXTENSION to place into dump file.
  216. N.B. This overrides a value we may find in DeviceObject->DeviceObjectExtension
  217. Dope - DEVICE_OBJECT_POWER_EXTENSION to place into the dump file.
  218. N.B. This overrides a value we may find in Doe->Dope (or by induction, DeviceObject->DeviceObjectExtension->Dope
  219. Return Value:
  220. None
  221. --*/
  222. {
  223. PDRIVER_OBJECT lPDriverObject = NULL;
  224. PDEVOBJ_EXTENSION lPDoe = NULL;
  225. PDEVICE_OBJECT_POWER_EXTENSION lPDope = NULL;
  226. //
  227. // Insert any parameters that were sent in.
  228. //
  229. if( DataBlock ) {
  230. IoAddTriageDumpDataBlock(
  231. PAGE_ALIGN(DataBlock),
  232. (DataBlockSize ? BYTES_TO_PAGES(DataBlockSize) : PAGE_SIZE) );
  233. }
  234. if( DeviceObject ) {
  235. IoAddTriageDumpDataBlock(DeviceObject, sizeof(DEVICE_OBJECT));
  236. }
  237. if( DriverObject ) {
  238. lPDriverObject = DriverObject;
  239. } else if( (DeviceObject) && (DeviceObject->DriverObject) ) {
  240. lPDriverObject = DeviceObject->DriverObject;
  241. }
  242. if( lPDriverObject ) {
  243. IoAddTriageDumpDataBlock(lPDriverObject, lPDriverObject->Size);
  244. if( lPDriverObject->DriverName.Buffer ) {
  245. IoAddTriageDumpDataBlock(lPDriverObject->DriverName.Buffer, lPDriverObject->DriverName.Length);
  246. }
  247. }
  248. if( Doe ) {
  249. lPDoe = Doe;
  250. } else if( DeviceObject ) {
  251. lPDoe = DeviceObject->DeviceObjectExtension;
  252. }
  253. if( lPDoe ) {
  254. IoAddTriageDumpDataBlock(PAGE_ALIGN(lPDoe), sizeof(DEVOBJ_EXTENSION));
  255. if( lPDoe->DeviceNode ) {
  256. IoAddTriageDumpDataBlock(PAGE_ALIGN(lPDoe->DeviceNode), PAGE_SIZE);
  257. }
  258. if( lPDoe->AttachedTo ) {
  259. IoAddTriageDumpDataBlock(PAGE_ALIGN(lPDoe->AttachedTo), PAGE_SIZE);
  260. }
  261. if( lPDoe->Vpb ) {
  262. IoAddTriageDumpDataBlock(PAGE_ALIGN(lPDoe->Vpb), PAGE_SIZE);
  263. }
  264. }
  265. if( Dope ) {
  266. lPDope = Dope;
  267. } else if( lPDoe ) {
  268. lPDope = lPDoe->Dope;
  269. }
  270. if( lPDope ) {
  271. IoAddTriageDumpDataBlock(PAGE_ALIGN(lPDope), sizeof(DEVICE_OBJECT_POWER_EXTENSION));
  272. }
  273. //
  274. // Globals that may be of interest.
  275. //
  276. IoAddTriageDumpDataBlock(PAGE_ALIGN(&PopHiberFile), sizeof(POP_HIBER_FILE));
  277. IoAddTriageDumpDataBlock(PAGE_ALIGN(&PopAction), sizeof(POP_POWER_ACTION));
  278. if(PopAction.DevState) {
  279. IoAddTriageDumpDataBlock(PAGE_ALIGN(&(PopAction.DevState)), sizeof(POP_DEVICE_SYS_STATE));
  280. }
  281. if(PopAction.HiberContext) {
  282. IoAddTriageDumpDataBlock(PAGE_ALIGN(&(PopAction.HiberContext)), sizeof(POP_HIBER_CONTEXT));
  283. }
  284. IoAddTriageDumpDataBlock(PAGE_ALIGN(&PopCB), sizeof(POP_COMPOSITE_BATTERY));
  285. if(PopCB.StatusIrp) {
  286. IoAddTriageDumpDataBlock(PAGE_ALIGN(&(PopCB.StatusIrp)), sizeof(IRP));
  287. }
  288. IoAddTriageDumpDataBlock(PAGE_ALIGN(PopAttributes), sizeof(POP_STATE_ATTRIBUTE) * POP_NUMBER_ATTRIBUTES);
  289. }
  290. VOID
  291. FASTCALL
  292. _PopInternalError (
  293. IN ULONG BugCode
  294. )
  295. {
  296. KeBugCheckEx (INTERNAL_POWER_ERROR, 0x2, BugCode, 0, 0);
  297. }
  298. EXCEPTION_DISPOSITION
  299. PopExceptionFilter (
  300. IN PEXCEPTION_POINTERS ExceptionInfo,
  301. IN BOOLEAN AllowRaisedException
  302. )
  303. {
  304. //
  305. // If handler wants raised expceptions, check the exception code
  306. //
  307. if (AllowRaisedException) {
  308. switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
  309. case STATUS_INVALID_PARAMETER:
  310. case STATUS_INVALID_PARAMETER_1:
  311. case STATUS_INVALID_PARAMETER_2:
  312. return EXCEPTION_EXECUTE_HANDLER;
  313. }
  314. }
  315. //
  316. // Not allowed
  317. //
  318. PoPrint (PO_ERROR, ("PoExceptionFilter: exr %x, cxr %x",
  319. ExceptionInfo->ExceptionRecord,
  320. ExceptionInfo->ContextRecord
  321. ));
  322. PopInternalAddToDumpFile( ExceptionInfo->ExceptionRecord,
  323. sizeof(EXCEPTION_RECORD),
  324. NULL,
  325. NULL,
  326. NULL,
  327. NULL );
  328. PopInternalAddToDumpFile( ExceptionInfo->ContextRecord,
  329. sizeof(CONTEXT),
  330. NULL,
  331. NULL,
  332. NULL,
  333. NULL );
  334. KeBugCheckEx( INTERNAL_POWER_ERROR,
  335. 0x101,
  336. POP_MISC,
  337. (ULONG_PTR)ExceptionInfo,
  338. 0 );
  339. }
  340. PUCHAR
  341. PopSystemStateString(
  342. IN SYSTEM_POWER_STATE SystemState
  343. )
  344. // This function is not DBG because...
  345. {
  346. PUCHAR p;
  347. switch (SystemState) {
  348. case PowerSystemUnspecified: p = "Unspecified"; break;
  349. case PowerSystemWorking: p = "Working"; break;
  350. case PowerSystemSleeping1: p = "Sleeping1"; break;
  351. case PowerSystemSleeping2: p = "Sleeping2"; break;
  352. case PowerSystemSleeping3: p = "Sleeping3"; break;
  353. case PowerSystemHibernate: p = "Hibernate"; break;
  354. case PowerSystemShutdown: p = "Shutdown"; break;
  355. default: p = "?";
  356. }
  357. return p;
  358. }
  359. #if DBG
  360. PUCHAR
  361. PopPowerActionString(
  362. IN POWER_ACTION PowerAction
  363. )
  364. // This function is not DBG because...
  365. {
  366. PUCHAR p;
  367. switch (PowerAction) {
  368. case PowerActionNone: p = "None"; break;
  369. case PowerActionSleep: p = "Sleep"; break;
  370. case PowerActionHibernate: p = "Hibernate"; break;
  371. case PowerActionShutdown: p = "Shutdown"; break;
  372. case PowerActionShutdownReset: p = "ShutdownReset"; break;
  373. case PowerActionShutdownOff: p = "ShutdownOff"; break;
  374. case PowerActionWarmEject: p = "WarmEject"; break;
  375. default: p = "?";
  376. }
  377. return p;
  378. }
  379. #endif
  380. #if DBG
  381. //
  382. // PowerTrace variables
  383. //
  384. ULONG PoPowerTraceControl = 0L;
  385. ULONG PoPowerTraceCount = 0L;
  386. PUCHAR PoPowerTraceMinorCode[] = {
  387. "wait", "seq", "set", "query"
  388. };
  389. PUCHAR PoPowerTracePoint[] = {
  390. "calldrv", "present", "startnxt", "setstate", "complete"
  391. };
  392. PUCHAR PoPowerType[] = {
  393. "sys", "dev"
  394. };
  395. VOID
  396. PoPowerTracePrint(
  397. ULONG TracePoint,
  398. ULONG_PTR Caller,
  399. ULONG_PTR CallerCaller,
  400. ULONG_PTR DeviceObject,
  401. ULONG_PTR Arg1,
  402. ULONG_PTR Arg2
  403. )
  404. /*
  405. Example:
  406. PLOG,00015,startnxt,c@ffea1345,cc@ffea5643,do@80081234,irp@8100ff00,ios@8100ff10,query,sys,3
  407. */
  408. {
  409. PIO_STACK_LOCATION Isp;
  410. PUCHAR tracename;
  411. ULONG j;
  412. ULONG tp;
  413. PoPowerTraceCount++;
  414. if (PoPowerTraceControl & TracePoint) {
  415. tracename = NULL;
  416. tp = TracePoint;
  417. for (j = 0; j < 33; tp = tp >> 1, j = j+1)
  418. {
  419. if (tp & 1) {
  420. tracename = PoPowerTracePoint[j];
  421. j = 33;
  422. }
  423. }
  424. DbgPrint("PLOG,%05ld,%8s,do@%08lx",
  425. PoPowerTraceCount,tracename,DeviceObject
  426. );
  427. if ((TracePoint == POWERTRACE_CALL) ||
  428. (TracePoint == POWERTRACE_PRESENT) ||
  429. (TracePoint == POWERTRACE_STARTNEXT))
  430. {
  431. DbgPrint(",irp@%08lx,isp@%08lx",Arg1,Arg2);
  432. Isp = (PIO_STACK_LOCATION)Arg2;
  433. DbgPrint(",%5s", PoPowerTraceMinorCode[Isp->MinorFunction]);
  434. if ((Isp->MinorFunction == IRP_MN_SET_POWER) ||
  435. (Isp->MinorFunction == IRP_MN_QUERY_POWER))
  436. {
  437. DbgPrint(",%s,%d",
  438. PoPowerType[Isp->Parameters.Power.Type],
  439. ((ULONG)Isp->Parameters.Power.State.DeviceState)-1 // hack - works for sys state too
  440. );
  441. }
  442. } else if (TracePoint == POWERTRACE_SETSTATE) {
  443. DbgPrint(",,,,%s,%d", PoPowerType[Arg1], Arg2-1);
  444. } else if (TracePoint == POWERTRACE_COMPLETE) {
  445. DbgPrint(",irp@%08lx,isp@%08lx",Arg1,Arg2);
  446. }
  447. DbgPrint("\n");
  448. }
  449. return;
  450. }
  451. #endif
  452. ULONG PoSimpleCheck(IN ULONG PartialSum,
  453. IN PVOID SourceVa,
  454. IN ULONG_PTR Length)
  455. {
  456. // Just use the TCP/IP check sum
  457. //
  458. return tcpxsum(PartialSum, (PUCHAR)SourceVa, Length);
  459. }
  460. NTSTATUS
  461. PopOpenPowerKey (
  462. OUT PHANDLE Handle
  463. )
  464. /*++
  465. Routine Description:
  466. Open and return the handle to the power policy key in the registry
  467. Arguments:
  468. Handle - Handle to power policy key
  469. Return Value:
  470. Status
  471. --*/
  472. {
  473. UNICODE_STRING UnicodeString;
  474. OBJECT_ATTRIBUTES ObjectAttributes;
  475. NTSTATUS Status;
  476. HANDLE BaseHandle;
  477. ULONG disposition;
  478. //
  479. // Open current control set
  480. //
  481. InitializeObjectAttributes(
  482. &ObjectAttributes,
  483. &CmRegistryMachineSystemCurrentControlSet,
  484. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  485. NULL,
  486. (PSECURITY_DESCRIPTOR) NULL
  487. );
  488. Status = ZwOpenKey (
  489. &BaseHandle,
  490. KEY_READ | KEY_WRITE,
  491. &ObjectAttributes
  492. );
  493. if (!NT_SUCCESS(Status)) {
  494. return Status;
  495. }
  496. //
  497. // Open power branch
  498. //
  499. RtlInitUnicodeString (&UnicodeString, PopRegKey);
  500. InitializeObjectAttributes(
  501. &ObjectAttributes,
  502. &UnicodeString,
  503. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  504. BaseHandle,
  505. (PSECURITY_DESCRIPTOR) NULL
  506. );
  507. Status = ZwCreateKey (
  508. Handle,
  509. KEY_READ | KEY_WRITE,
  510. &ObjectAttributes,
  511. 0,
  512. (PUNICODE_STRING) NULL,
  513. REG_OPTION_NON_VOLATILE,
  514. &disposition
  515. );
  516. ZwClose (BaseHandle);
  517. return Status;
  518. }
  519. VOID
  520. PopInitializePowerPolicySimulate(
  521. VOID
  522. )
  523. /*++
  524. Routine Description:
  525. Reads PopSimulate out of the registry. Also applies any overrides that might
  526. be required as a result of the installed system (hydra for example)
  527. Arguments:
  528. NONE.
  529. Return Value:
  530. Status
  531. --*/
  532. {
  533. UNICODE_STRING UnicodeString;
  534. OBJECT_ATTRIBUTES ObjectAttributes;
  535. NTSTATUS Status;
  536. HANDLE BaseHandle;
  537. HANDLE Handle;
  538. ULONG Length;
  539. ULONG disposition;
  540. struct {
  541. KEY_VALUE_PARTIAL_INFORMATION Inf;
  542. ULONG Data;
  543. } PartialInformation;
  544. PAGED_CODE();
  545. //
  546. // Open current control set
  547. //
  548. InitializeObjectAttributes(
  549. &ObjectAttributes,
  550. &CmRegistryMachineSystemCurrentControlSet,
  551. OBJ_CASE_INSENSITIVE,
  552. NULL,
  553. (PSECURITY_DESCRIPTOR) NULL
  554. );
  555. Status = ZwOpenKey(
  556. &BaseHandle,
  557. KEY_READ,
  558. &ObjectAttributes
  559. );
  560. if (!NT_SUCCESS(Status)) {
  561. goto done;
  562. }
  563. // Get the right key
  564. RtlInitUnicodeString (&UnicodeString, PopSimulateRegKey);
  565. InitializeObjectAttributes(
  566. &ObjectAttributes,
  567. &UnicodeString,
  568. OBJ_CASE_INSENSITIVE,
  569. BaseHandle,
  570. (PSECURITY_DESCRIPTOR) NULL
  571. );
  572. Status = ZwCreateKey(
  573. &Handle,
  574. KEY_READ,
  575. &ObjectAttributes,
  576. 0,
  577. (PUNICODE_STRING) NULL,
  578. REG_OPTION_NON_VOLATILE,
  579. &disposition
  580. );
  581. ZwClose(BaseHandle);
  582. if(!NT_SUCCESS(Status)) {
  583. goto done;
  584. }
  585. //
  586. // Get the value of the simulation
  587. //
  588. RtlInitUnicodeString (&UnicodeString,PopSimulateRegName);
  589. Status = ZwQueryValueKey(
  590. Handle,
  591. &UnicodeString,
  592. KeyValuePartialInformation,
  593. &PartialInformation,
  594. sizeof (PartialInformation),
  595. &Length
  596. );
  597. ZwClose (Handle);
  598. if (!NT_SUCCESS(Status)) {
  599. goto done;
  600. }
  601. //
  602. // Check to make sure the retrieved data makes sense
  603. //
  604. if(PartialInformation.Inf.DataLength != sizeof(ULONG)) {
  605. goto done;
  606. }
  607. //
  608. // Initialize PopSimulate
  609. //
  610. PopSimulate = *((PULONG)(PartialInformation.Inf.Data));
  611. done:
  612. return;
  613. }
  614. VOID
  615. PopSaveHeuristics (
  616. VOID
  617. )
  618. /*++
  619. Routine Description:
  620. Open and return the handle to the power policy key in the registry
  621. Arguments:
  622. Handle - Handle to power policy key
  623. Return Value:
  624. Status
  625. --*/
  626. {
  627. HANDLE handle;
  628. UNICODE_STRING UnicodeString;
  629. OBJECT_ATTRIBUTES ObjectAttributes;
  630. NTSTATUS Status;
  631. ASSERT_POLICY_LOCK_OWNED();
  632. Status = PopOpenPowerKey (&handle);
  633. if (NT_SUCCESS(Status)) {
  634. PopHeuristics.Dirty = FALSE;
  635. RtlInitUnicodeString (&UnicodeString, PopHeuristicsRegName);
  636. Status = ZwSetValueKey (
  637. handle,
  638. &UnicodeString,
  639. 0L,
  640. REG_BINARY,
  641. &PopHeuristics,
  642. sizeof (PopHeuristics)
  643. );
  644. ZwClose(handle);
  645. }
  646. }
  647. VOID
  648. PoInvalidateDevicePowerRelations(
  649. PDEVICE_OBJECT DeviceObject
  650. )
  651. /*++
  652. Routine Description:
  653. This routine is called by IoInvalidateDeviceRelations when the
  654. type of invalidation is for power relations.
  655. It will will knock down the notify network around the supplied
  656. device object.
  657. Arguments:
  658. DeviceObject - supplies the address of the device object whose
  659. power relations are now invalid.
  660. Return Value:
  661. None.
  662. --*/
  663. {
  664. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  665. PopRunDownSourceTargetList(DeviceObject);
  666. return;
  667. }
  668. NTSTATUS
  669. PoGetLightestSystemStateForEject(
  670. IN BOOLEAN DockBeingEjected,
  671. IN BOOLEAN HotEjectSupported,
  672. IN BOOLEAN WarmEjectSupported,
  673. OUT PSYSTEM_POWER_STATE LightestSleepState
  674. )
  675. /*++
  676. Routine Description:
  677. This routine is called by ntos\pnp\pnpevent.c to determine the lightest
  678. sleep state an eject operation can be executed in. This function is to be
  679. called after all appropriate batteries/power adapters have been *removed*,
  680. but before the eject has occured.
  681. Arguments:
  682. DockBeingEjected - TRUE iff a dock is among the items that may be
  683. ejected.
  684. HotEjectSupported - TRUE if the device being ejected supports S0 VCR
  685. style eject.
  686. WarmEjectSupported - TRUE if the device being ejected supports S1-S4
  687. style warm ejection.
  688. LightestSleepState - Set to the lightest sleep state the device can be
  689. ejected in. On error, this is set to
  690. PowerSystemUnspecified.
  691. N.B. If both HotEjectSupported and WarmEjectSupported are FALSE, it is
  692. assumed this device is "user" ejectable in S0 (ie. Hot ejectable).
  693. Return Value:
  694. NTSTATUS - If there is insufficient power to do the indicated operation,
  695. STATUS_INSUFFICIENT_POWER is returned.
  696. --*/
  697. {
  698. SYSTEM_BATTERY_STATE systemBatteryInfo;
  699. UNICODE_STRING unicodeString;
  700. OBJECT_ATTRIBUTES objectAttributes;
  701. NTSTATUS status;
  702. HANDLE handle;
  703. ULONG length;
  704. ULONG currentPercentage;
  705. ULONG disposition;
  706. UCHAR ejectPartialInfo[SIZEOF_EJECT_PARTIAL_INFO];
  707. PUNDOCK_POWER_RESTRICTIONS undockRestrictions;
  708. PKEY_VALUE_PARTIAL_INFORMATION partialInfoHeader;
  709. PAGED_CODE();
  710. //
  711. // Preinit sleep to failure.
  712. //
  713. *LightestSleepState = PowerSystemUnspecified;
  714. //
  715. // If neither, then it's a "user" assisted hot eject.
  716. //
  717. if ((!HotEjectSupported) && (!WarmEjectSupported)) {
  718. HotEjectSupported = TRUE;
  719. }
  720. //
  721. // If it's not a dock device being ejected, we assume no great changes
  722. // in power will occur after the eject. Therefore our policy is simple,
  723. // if we can't do hot eject, we'll try warm eject in the best possible
  724. // sleep state.
  725. //
  726. if (!DockBeingEjected) {
  727. if (HotEjectSupported) {
  728. *LightestSleepState = PowerSystemWorking;
  729. } else {
  730. ASSERT(WarmEjectSupported);
  731. *LightestSleepState = PowerSystemSleeping1;
  732. }
  733. return STATUS_SUCCESS;
  734. }
  735. //
  736. // We are going to eject a dock, so we retrieve our undock power policy.
  737. //
  738. status = PopOpenPowerKey (&handle);
  739. if (!NT_SUCCESS(status)) {
  740. return status;
  741. }
  742. // Get the right key
  743. RtlInitUnicodeString (&unicodeString, PopUndockPolicyRegName);
  744. status = ZwQueryValueKey (
  745. handle,
  746. &unicodeString,
  747. KeyValuePartialInformation,
  748. &ejectPartialInfo,
  749. sizeof (ejectPartialInfo),
  750. &length
  751. );
  752. ZwClose (handle);
  753. if ((!NT_SUCCESS(status)) && (status != STATUS_OBJECT_NAME_NOT_FOUND)) {
  754. return status;
  755. }
  756. // Check to make sure the retrieved data makes sense
  757. partialInfoHeader = (PKEY_VALUE_PARTIAL_INFORMATION) ejectPartialInfo;
  758. undockRestrictions =
  759. (PUNDOCK_POWER_RESTRICTIONS) (ejectPartialInfo + SIZEOF_PARTIAL_INFO_HEADER);
  760. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  761. //
  762. // These defaults match Win9x behavior. 0% for sleep undock means
  763. // we always allow undock into Sx. This is bad for some laptops, but
  764. // legal for those that have reserve power we don't see.
  765. //
  766. undockRestrictions->HotUndockMinimumCapacity = 10; // In percent
  767. undockRestrictions->SleepUndockMinimumCapacity = 0; // In percent
  768. } else if (partialInfoHeader->DataLength <
  769. FIELD_OFFSET(UNDOCK_POWER_RESTRICTIONS, HotUndockMinimumCapacity)) {
  770. return STATUS_REGISTRY_CORRUPT;
  771. } else if (undockRestrictions->Version != 1) {
  772. //
  773. // We cannot interpret the information stored in the registry. Bail.
  774. //
  775. return STATUS_UNSUCCESSFUL;
  776. } else if ((partialInfoHeader->DataLength < sizeof(UNDOCK_POWER_RESTRICTIONS)) ||
  777. (undockRestrictions->Size != partialInfoHeader->DataLength)) {
  778. //
  779. // Malformed for version 1.
  780. //
  781. return STATUS_REGISTRY_CORRUPT;
  782. }
  783. //
  784. // Retrieve all the fun battery info. Note that we do not examine the
  785. // AC power adapter information as the best bus we have today (ACPI) doesn't
  786. // let us know if an AC adapter is leaving when we undock (so we assume all
  787. // will). If the vendor *did* put his adapter in the AML namespace, we would
  788. // enter CRITICAL shutdown immediately upon change driver in our current
  789. // design.
  790. //
  791. status = NtPowerInformation(
  792. SystemBatteryState,
  793. NULL,
  794. 0,
  795. &systemBatteryInfo,
  796. sizeof(systemBatteryInfo)
  797. ) ;
  798. if (!NT_SUCCESS(status)) {
  799. return status;
  800. }
  801. //
  802. // Convert current capacity in milliwatt hours to percentage remaining. We
  803. // should really make a decision based on the amount of time remaining under
  804. // peak milliwatt usage, but we do not collect enough information for this
  805. // today...
  806. //
  807. if (systemBatteryInfo.MaxCapacity == 0) {
  808. currentPercentage = 0;
  809. } else {
  810. //
  811. // Did we "wrap" around?
  812. //
  813. if ((systemBatteryInfo.RemainingCapacity * 100) <=
  814. systemBatteryInfo.RemainingCapacity) {
  815. currentPercentage = 0;
  816. } else {
  817. currentPercentage = (systemBatteryInfo.RemainingCapacity * 100)/
  818. systemBatteryInfo.MaxCapacity;
  819. }
  820. }
  821. //
  822. // Pick the appropriate sleep state based on our imposed limits.
  823. //
  824. if ((currentPercentage >= undockRestrictions->HotUndockMinimumCapacity) &&
  825. HotEjectSupported) {
  826. *LightestSleepState = PowerSystemWorking;
  827. } else if (WarmEjectSupported) {
  828. if (currentPercentage >= undockRestrictions->SleepUndockMinimumCapacity) {
  829. *LightestSleepState = PowerSystemSleeping1;
  830. } else {
  831. *LightestSleepState = PowerSystemHibernate;
  832. }
  833. } else {
  834. status = STATUS_INSUFFICIENT_POWER;
  835. }
  836. return status;
  837. }
  838. VOID
  839. PoGetDevicePowerState(
  840. IN PDEVICE_OBJECT PhysicalDeviceObject,
  841. OUT DEVICE_POWER_STATE *DevicePowerState
  842. )
  843. /*++
  844. Routine Description:
  845. This routine gets the power state of a given device. The object should be
  846. the Physical Device Object for a *Started* WDM device stack.
  847. Arguments:
  848. PhysicalDeviceObject - Device object representing the bottom of a WDM
  849. device stack.
  850. DevicePowerState - Receives the power state of the given device.
  851. Return Value:
  852. None.
  853. --*/
  854. {
  855. PDEVOBJ_EXTENSION doe;
  856. DEVICE_POWER_STATE deviceState;
  857. PAGED_CODE();
  858. doe = PhysicalDeviceObject->DeviceObjectExtension;
  859. deviceState = PopLockGetDoDevicePowerState(doe);
  860. if (deviceState == PowerDeviceUnspecified) {
  861. //
  862. // The PDO isn't bothering to call PoSetPowerState. Since this API
  863. // shouldn't be called on non-started devices, we will call it D0.
  864. //
  865. deviceState = PowerDeviceD0;
  866. }
  867. *DevicePowerState = deviceState;
  868. }
  869. VOID
  870. PopUnlockAfterSleepWorker(
  871. IN PVOID NotUsed
  872. )
  873. /*++
  874. Routine Description:
  875. This work item performs the unlocking of code and worker threads that
  876. corresponds to the locking done at the beginning of NtSetSystemPowerState.
  877. The unlocking is queued off to a delayed worker thread because it is likely
  878. to block on disk I/O, which will force the resume to get stuck waiting for
  879. the disks to spin up.
  880. Arguments:
  881. NotUsed - not used
  882. Return Value:
  883. None
  884. --*/
  885. {
  886. MmUnlockPagableImageSection(ExPageLockHandle);
  887. ExSwapinWorkerThreads(TRUE);
  888. ExNotifyCallback (ExCbPowerState, (PVOID) PO_CB_SYSTEM_STATE_LOCK, (PVOID) 1);
  889. //
  890. // Signal that unlocking is done and it is safe to lock again.
  891. //
  892. KeSetEvent(&PopUnlockComplete, 0, FALSE);
  893. }