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.

968 lines
28 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. pbatt.c
  5. Abstract:
  6. This module interfaces the policy manager to the composite device
  7. Author:
  8. Ken Reneris (kenr) 17-Jan-1997
  9. Revision History:
  10. --*/
  11. #include "pop.h"
  12. //
  13. // Internal prototypes
  14. //
  15. VOID
  16. PopRecalculateCBTriggerLevels (
  17. ULONG Flags
  18. );
  19. VOID
  20. PopComputeCBTime (
  21. VOID
  22. );
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text(PAGE, PopRecalculateCBTriggerLevels)
  25. #pragma alloc_text(PAGE, PopCompositeBatteryDeviceHandler)
  26. #pragma alloc_text(PAGE, PopComputeCBTime)
  27. #pragma alloc_text(PAGE, PopResetCBTriggers)
  28. #pragma alloc_text(PAGE, PopCurrentPowerState)
  29. #endif
  30. VOID
  31. PopCompositeBatteryUpdateThrottleLimit(
  32. IN ULONG CurrentCapacity
  33. )
  34. /*++
  35. Routine Description:
  36. This routine is called to update the ThrottleLimit in each of the
  37. processor's PRCB to reflect the maximum given the change in current
  38. capacity.
  39. This function was broken out because it cannot be paged code
  40. Arguments:
  41. CurrentCapacity - PercentageCapacity remaining...
  42. Return Value:
  43. None
  44. --*/
  45. {
  46. KAFFINITY currentAffinity;
  47. KAFFINITY processors;
  48. PPROCESSOR_PERF_STATE perfStates;
  49. PPROCESSOR_POWER_STATE pState;
  50. ULONG perfStatesCount;
  51. ULONG i;
  52. KIRQL oldIrql;
  53. #if DBG
  54. ULONGLONG currentTime;
  55. UCHAR t[40];
  56. currentTime = KeQueryInterruptTime();
  57. PopTimeString(t, currentTime);
  58. #endif
  59. currentAffinity = 1;
  60. processors = KeActiveProcessors;
  61. while (processors) {
  62. if (!(processors & currentAffinity)) {
  63. currentAffinity <<= 1;
  64. continue;
  65. }
  66. KeSetSystemAffinityThread( currentAffinity );
  67. processors &= ~currentAffinity;
  68. currentAffinity <<= 1;
  69. //
  70. // We need to be running at DISPATCH_LEVEL to access the
  71. // structures referenced within the pState...
  72. //
  73. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  74. pState = &(KeGetCurrentPrcb()->PowerState);
  75. //
  76. // Does this processor support throttling?
  77. //
  78. if ((pState->Flags & PSTATE_SUPPORTS_THROTTLE) == 0) {
  79. //
  80. // No, then we don't care about it...
  81. //
  82. KeLowerIrql( oldIrql );
  83. continue;
  84. }
  85. //
  86. // Look at the power structure and get the array of
  87. // perf states supported. Note that we change the
  88. // perfStatesCount by subtracting one so that we don't
  89. // have to worry about overrruning the array during
  90. // the for loop
  91. //
  92. pState = &(KeGetCurrentPrcb()->PowerState);
  93. perfStates = pState->PerfStates;
  94. perfStatesCount = (pState->PerfStatesCount - 1);
  95. //
  96. // See which throttle point is best for this power
  97. // capacity. Note that we have pre-calculated which
  98. // capacity matches which state, so its only a matter
  99. // of walking the array...
  100. //
  101. for (i = pState->KneeThrottleIndex; i < perfStatesCount; i++) {
  102. if (perfStates[i].MinCapacity <= CurrentCapacity) {
  103. break;
  104. }
  105. }
  106. //
  107. // Update the throttle limit index
  108. //
  109. if (pState->ThrottleLimitIndex != i) {
  110. pState->ThrottleLimitIndex = (UCHAR) i;
  111. #if DBG
  112. PoPrint(
  113. PO_THROTTLE,
  114. ("PopApplyThermalThrottle - %s - New Limit (%d) Index (%d)\n",
  115. t,perfStates[i].PercentFrequency,i)
  116. );
  117. #endif
  118. //
  119. // Force a throttle update
  120. //
  121. PopUpdateProcessorThrottle();
  122. }
  123. //
  124. // Revert back to our previous IRQL
  125. //
  126. KeLowerIrql( oldIrql );
  127. } // while
  128. //
  129. // Revert to the affinity of the original thread
  130. //
  131. KeRevertToUserAffinityThread();
  132. }
  133. VOID
  134. PopCompositeBatteryDeviceHandler (
  135. IN PDEVICE_OBJECT DeviceObject,
  136. IN PIRP Irp,
  137. IN PVOID Context
  138. )
  139. /*++
  140. Routine Description:
  141. This function is the irp handler function to handle the completion
  142. if the composite battery irp. When there is a composite battery
  143. present one IRP is always outstanding to the device. On completion
  144. this IRP is recycled to the next request.
  145. N.B. PopPolicyLock must be held.
  146. Arguments:
  147. DeviceObject - DeviceObject of the battery device
  148. Irp - Irp which has completed
  149. Context - n/a
  150. Return Value:
  151. None.
  152. --*/
  153. {
  154. PIO_STACK_LOCATION IrpSp, IrpPrevSp;
  155. PVOID InputBuffer, OutputBuffer;
  156. ULONG InputBufferLength, OutputBufferLength;
  157. ULONG IoctlCode;
  158. PSYSTEM_POWER_POLICY Policy;
  159. PPROCESSOR_POWER_POLICY ProcessorPolicy;
  160. ULONG i, j;
  161. NTSTATUS Status;
  162. ULONG currentCapacity;
  163. #if DBG
  164. ULONGLONG currentTime;
  165. UCHAR t[40];
  166. currentTime = KeQueryInterruptTime();
  167. PopTimeString(t, currentTime);
  168. #endif
  169. ASSERT_POLICY_LOCK_OWNED();
  170. ASSERT (Irp == PopCB.StatusIrp);
  171. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  172. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  173. //
  174. // Handle the completed request
  175. //
  176. switch (PopCB.State) {
  177. case PO_CB_READ_TAG:
  178. case PO_CB_WAIT_TAG:
  179. // tag is now valid, read info
  180. PoPrint(PO_BATT, ("PopCB: New battery tag\n"));
  181. //
  182. // Reset the triggers.
  183. //
  184. // We reset PO_TRG_SET, so the level will be recalculated, but on
  185. // battery tag change we don't want to make the actions happen again.
  186. // If the trigger has not yet been set off, it will still be armed.
  187. //
  188. PopResetCBTriggers (PO_TRG_SET);
  189. PopCB.State = PO_CB_READ_INFO;
  190. PopCB.Tag = PopCB.u.Tag;
  191. // Ensure that the power state passed in is bad, so QUERY_STATUS
  192. // will return immediately.
  193. PopCB.Status.PowerState = (ULONG) -1;
  194. break;
  195. case PO_CB_READ_INFO:
  196. // info is read directly into buffer
  197. PoPrint(PO_BATT, ("PopCB: info read\n"));
  198. PopCB.State = PO_CB_READ_STATUS;
  199. RtlCopyMemory (&PopCB.Info, &PopCB.u.Info, sizeof(PopCB.Info));
  200. break;
  201. case PO_CB_READ_STATUS:
  202. //
  203. // Status has been read, check it
  204. //
  205. PoPrint(PO_BATT, ("PopCB: Status PwrState %x, Cap %x, Volt %x, Cur %x\n",
  206. PopCB.u.Status.PowerState,
  207. PopCB.u.Status.Capacity,
  208. PopCB.u.Status.Voltage,
  209. PopCB.u.Status.Current
  210. ));
  211. PopCB.StatusTime = KeQueryInterruptTime();
  212. //
  213. // Check if the current policy should be ac or dc
  214. //
  215. if (PopCB.u.Status.PowerState & BATTERY_POWER_ON_LINE) {
  216. ProcessorPolicy = &PopAcProcessorPolicy;
  217. Policy = &PopAcPolicy;
  218. } else {
  219. ProcessorPolicy = &PopDcProcessorPolicy;
  220. Policy = &PopDcPolicy;
  221. }
  222. //
  223. // Did the policy change?
  224. //
  225. if (PopPolicy != Policy || PopProcessorPolicy != ProcessorPolicy) {
  226. //
  227. // Change the active policy and reset the battery triggers
  228. //
  229. PopProcessorPolicy = ProcessorPolicy;
  230. PopPolicy = Policy;
  231. //
  232. // Reset triggers.
  233. //
  234. // In this case we re-arm both the user and system triggers.
  235. // The system trigger will be disarmed when we recalculate
  236. // trigger levels if the capacity was already below that level.
  237. //
  238. PopResetCBTriggers (PO_TRG_SET | PO_TRG_USER | PO_TRG_SYSTEM);
  239. PopSetNotificationWork (
  240. PO_NOTIFY_ACDC_CALLBACK |
  241. PO_NOTIFY_POLICY |
  242. PO_NOTIFY_PROCESSOR_POLICY
  243. );
  244. //
  245. // Recompute thermal throttle and cooling mode
  246. //
  247. // Note that PopApplyThermalThrottle will take care of any dynamic
  248. // throttling that might need to happen due to the AC/DC transition.
  249. //
  250. PopApplyThermalThrottle ();
  251. PopIdleUpdateIdleHandlers();
  252. //
  253. // Recompute system idle values
  254. //
  255. PopInitSIdle ();
  256. }
  257. //
  258. // Did battery cross resolution setting?
  259. // Correction... Has it changed at all. If so, all apps should be updated,
  260. // even if it hasn't crossed a resolution setting. Otherwise, if one app
  261. // queries the current status, it could be displaying a different value than
  262. // the battery meter.
  263. //
  264. if ((PopCB.u.Status.Capacity != PopCB.Status.Capacity) ||
  265. PopCB.Status.PowerState != PopCB.u.Status.PowerState) {
  266. PopSetNotificationWork (PO_NOTIFY_BATTERY_STATUS);
  267. PopCB.State = PO_CB_READ_EST_TIME;
  268. }
  269. PopRecalculateCBTriggerLevels (PO_TRG_SYSTEM);
  270. //
  271. // Update current battery status
  272. //
  273. memcpy (&PopCB.Status, &PopCB.u.Status, sizeof (PopCB.Status));
  274. //
  275. // Check for discharging and if any discharge policies have tripped
  276. //
  277. if (Policy == &PopDcPolicy) {
  278. for (i=0; i < PO_NUM_POWER_LEVELS; i++) {
  279. if (PopCB.Status.Capacity <= PopCB.Trigger[i].Battery.Level) {
  280. //
  281. // Fire this power action
  282. //
  283. PopSetPowerAction(
  284. &PopCB.Trigger[i],
  285. PO_NOTIFY_BATTERY_STATUS,
  286. &Policy->DischargePolicy[i].PowerPolicy,
  287. Policy->DischargePolicy[i].MinSystemState,
  288. SubstituteLightestOverallDownwardBounded
  289. );
  290. PopCB.State = PO_CB_READ_EST_TIME;
  291. } else {
  292. //
  293. // Clear the trigger for this event
  294. //
  295. PopCB.Trigger[i].Flags &= ~(PO_TRG_USER|PO_TRG_SYSTEM);
  296. }
  297. }
  298. //
  299. // Figure out what our current capacity is...
  300. //
  301. if (PopCB.Info.FullChargedCapacity) {
  302. currentCapacity = PopCB.Status.Capacity * 100 /
  303. PopCB.Info.FullChargedCapacity;
  304. } else {
  305. //
  306. // Assume that the battery is fully charged...
  307. // This will cause us to reset the throttle limiter
  308. //
  309. currentCapacity = 100;
  310. }
  311. } else {
  312. //
  313. // Assume that the battery is fully charged...
  314. // This will cause us to reset the throttle limiter
  315. //
  316. currentCapacity = 100;
  317. }
  318. //
  319. // This is kind of silly code to put in here, but since
  320. // want to minize our synchronization elsewhere, we have
  321. // to examine every processor's powerstate and update
  322. // the throttlelimitindex on each. This may be actually
  323. // a smarth thing to do if not all processors support
  324. // the same set of states
  325. //
  326. PopCompositeBatteryUpdateThrottleLimit( currentCapacity );
  327. //
  328. // If there's a thread waiting or if we notified user (since
  329. // the response to the notify will be to read the power status) for
  330. // power state, read the est time now else read new status
  331. //
  332. if (PopCB.ThreadWaiting) {
  333. PopCB.State = PO_CB_READ_EST_TIME;
  334. }
  335. break;
  336. case PO_CB_READ_EST_TIME:
  337. //
  338. // Estimated time is read after sucessful status
  339. // read and (currently) only when there's a thread
  340. // waiting for the system power state
  341. //
  342. PoPrint(PO_BATT, ("PopCB: EstTime read\n"));
  343. PopCB.EstTime = PopCB.u.EstTime;
  344. PopCB.EstTimeTime = KeQueryInterruptTime();
  345. PopComputeCBTime();
  346. //
  347. // Signal waiting threads
  348. //
  349. PopCB.ThreadWaiting = FALSE;
  350. KeSetEvent (&PopCB.Event, 0, FALSE);
  351. //
  352. // Go back are read status
  353. //
  354. PopCB.State = PO_CB_READ_STATUS;
  355. break;
  356. default:
  357. PopInternalAddToDumpFile( Irp, sizeof(IRP), DeviceObject, NULL, NULL, NULL );
  358. KeBugCheckEx( INTERNAL_POWER_ERROR,
  359. 0x300,
  360. POP_BATT,
  361. (ULONG_PTR)DeviceObject,
  362. (ULONG_PTR)Irp );
  363. break;
  364. }
  365. } else {
  366. //
  367. // some sort of error, if the request was canceld re-issue
  368. // it else backup to reinitialize
  369. //
  370. if (Irp->IoStatus.Status != STATUS_CANCELLED) {
  371. //
  372. // This occurs under two circumstances. It is either the first time
  373. // through, or a battery was removed so the Irp failed dur to tag change.
  374. //
  375. //
  376. // If this is already a read-tag request then there's no battery present
  377. //
  378. PopCB.State = PopCB.State == PO_CB_READ_TAG ? PO_CB_WAIT_TAG : PO_CB_READ_TAG;
  379. PoPrint(PO_BATT, ("PopCB: error %x - new state %d\n",
  380. Irp->IoStatus.Status,
  381. PopCB.State
  382. ));
  383. } else {
  384. PoPrint(PO_BATT, ("PopCB: irp cancelled\n"));
  385. PopRecalculateCBTriggerLevels (PO_TRG_SYSTEM | PO_TRG_USER);
  386. }
  387. }
  388. //
  389. // If new state is none, then there's no battery
  390. //
  391. if (PopCB.State != PO_CB_NONE) {
  392. //
  393. // Issue new request based on current state
  394. //
  395. IrpSp = IoGetNextIrpStackLocation(Irp);
  396. IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  397. IoctlCode = IOCTL_BATTERY_QUERY_INFORMATION;
  398. PopCB.u.QueryInfo.BatteryTag = PopCB.Tag;
  399. InputBuffer = &PopCB.u.QueryInfo;
  400. InputBufferLength = sizeof(PopCB.u.QueryInfo);
  401. switch (PopCB.State) {
  402. case PO_CB_READ_TAG:
  403. PoPrint(PO_BATT, ("PopCB: query tag\n"));
  404. IoctlCode = IOCTL_BATTERY_QUERY_TAG;
  405. PopCB.u.Tag = (ULONG) 0;
  406. InputBufferLength = sizeof(ULONG);
  407. OutputBufferLength = sizeof(PopCB.Tag);
  408. break;
  409. case PO_CB_WAIT_TAG:
  410. PoPrint(PO_BATT, ("PopCB: query tag\n"));
  411. //
  412. // Battery is gone. Wait for it to appear
  413. //
  414. IoctlCode = IOCTL_BATTERY_QUERY_TAG;
  415. PopCB.u.Tag = (ULONG) -1;
  416. InputBufferLength = sizeof(ULONG);
  417. OutputBufferLength = sizeof(PopCB.Tag);
  418. //
  419. // Notify battery status change, and wake any threads
  420. //
  421. PopSetNotificationWork (PO_NOTIFY_BATTERY_STATUS);
  422. if (PopCB.ThreadWaiting) {
  423. PopCB.ThreadWaiting = FALSE;
  424. KeSetEvent (&PopCB.Event, 0, FALSE);
  425. }
  426. break;
  427. case PO_CB_READ_INFO:
  428. PoPrint(PO_BATT, ("PopCB: query info\n"));
  429. PopCB.u.QueryInfo.InformationLevel = BatteryInformation;
  430. OutputBufferLength = sizeof(PopCB.Info);
  431. break;
  432. case PO_CB_READ_STATUS:
  433. //
  434. // Calculate next wait
  435. //
  436. PopCB.u.Wait.BatteryTag = PopCB.Tag;
  437. PopCB.u.Wait.PowerState = PopCB.Status.PowerState;
  438. PopCB.u.Wait.Timeout = (ULONG) -1;
  439. if (PopCB.ThreadWaiting) {
  440. PopCB.u.Wait.Timeout = 0;
  441. }
  442. i = (PopCB.Info.FullChargedCapacity *
  443. PopPolicy->BroadcastCapacityResolution) / 100;
  444. if (!i) {
  445. i = 1;
  446. }
  447. if (PopCB.Status.Capacity > i) {
  448. PopCB.u.Wait.LowCapacity = PopCB.Status.Capacity - i;
  449. } else {
  450. PopCB.u.Wait.LowCapacity = 0;
  451. }
  452. PopCB.u.Wait.HighCapacity = PopCB.Status.Capacity + i;
  453. if (PopCB.u.Wait.HighCapacity < i) {
  454. // avoid rare case of overflow
  455. PopCB.u.Wait.HighCapacity = (ULONG) -1;
  456. }
  457. //
  458. // Check limits against power policies
  459. //
  460. for (i=0; i < PO_NUM_POWER_LEVELS; i++) {
  461. if (PopCB.Trigger[i].Flags & PO_TRG_SET) {
  462. if (PopCB.Trigger[i].Battery.Level < PopCB.Status.Capacity &&
  463. PopCB.Trigger[i].Battery.Level > PopCB.u.Wait.LowCapacity) {
  464. PopCB.u.Wait.LowCapacity = PopCB.Trigger[i].Battery.Level;
  465. }
  466. if (PopCB.Trigger[i].Battery.Level > PopCB.Status.Capacity &&
  467. PopCB.Trigger[i].Battery.Level < PopCB.u.Wait.HighCapacity) {
  468. PopCB.u.Wait.HighCapacity = PopCB.Trigger[i].Battery.Level;
  469. }
  470. }
  471. }
  472. IoctlCode = IOCTL_BATTERY_QUERY_STATUS;
  473. InputBuffer = &PopCB.u.Wait;
  474. InputBufferLength = sizeof(PopCB.u.Wait);
  475. OutputBufferLength = sizeof(PopCB.Status);
  476. PoPrint(PO_BATT, ("PopCB: timeout %x, pwrstate %x, low %x - high %x\n",
  477. PopCB.u.Wait.Timeout,
  478. PopCB.u.Wait.PowerState,
  479. PopCB.u.Wait.LowCapacity,
  480. PopCB.u.Wait.HighCapacity
  481. ));
  482. break;
  483. case PO_CB_READ_EST_TIME:
  484. PoPrint(PO_BATT, ("PopCB: query est time\n"));
  485. PopCB.u.QueryInfo.InformationLevel = BatteryEstimatedTime;
  486. PopCB.u.QueryInfo.AtRate = 0;
  487. OutputBufferLength = sizeof(PopCB.EstTime);
  488. break;
  489. default:
  490. PopInternalAddToDumpFile( IrpSp, sizeof(IO_STACK_LOCATION), DeviceObject, NULL, NULL, NULL );
  491. KeBugCheckEx( INTERNAL_POWER_ERROR,
  492. 0x301,
  493. POP_BATT,
  494. (ULONG_PTR)DeviceObject,
  495. (ULONG_PTR)IrpSp );
  496. break;
  497. }
  498. //
  499. // Submit IRP
  500. //
  501. IrpSp->Parameters.DeviceIoControl.IoControlCode = IoctlCode;
  502. IrpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
  503. IrpSp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
  504. Irp->AssociatedIrp.SystemBuffer = &PopCB.u;
  505. Irp->UserBuffer = &PopCB.u;
  506. Irp->PendingReturned = FALSE;
  507. Irp->Cancel = FALSE;
  508. IoSetCompletionRoutine (Irp, PopCompletePolicyIrp, NULL, TRUE, TRUE, TRUE);
  509. IoCallDriver (DeviceObject, Irp);
  510. } else {
  511. //
  512. // Battery has disappeared (state is PO_CB_NONE)
  513. //
  514. PoPrint(PO_BATT, ("PopCB: Battery removed\n"));
  515. PopSetNotificationWork (PO_NOTIFY_BATTERY_STATUS);
  516. //
  517. // Set policy to AC
  518. //
  519. if (PopPolicy != &PopAcPolicy) {
  520. PopPolicy = &PopAcPolicy;
  521. PopProcessorPolicy = &PopAcProcessorPolicy;
  522. PopSetNotificationWork(
  523. PO_NOTIFY_ACDC_CALLBACK |
  524. PO_NOTIFY_POLICY |
  525. PO_NOTIFY_PROCESSOR_POLICY
  526. );
  527. PopApplyThermalThrottle();
  528. PopIdleUpdateIdleHandlers();
  529. PopInitSIdle ();
  530. }
  531. //
  532. // Wake any threads
  533. //
  534. if (PopCB.ThreadWaiting) {
  535. PopCB.ThreadWaiting = FALSE;
  536. KeSetEvent (&PopCB.Event, 0, FALSE);
  537. }
  538. //
  539. // Cleanup
  540. //
  541. IoFreeIrp (Irp);
  542. PopCB.StatusIrp = NULL;
  543. ObDereferenceObject (DeviceObject);
  544. }
  545. }
  546. VOID
  547. PopRecalculateCBTriggerLevels (
  548. ULONG Flags
  549. )
  550. /*++
  551. Routine Description:
  552. This function is invoked to set the trigger battery levels based on the power
  553. policy. This will be invoked whenever the power policy is changed, or whenever
  554. there is a battery status change that could affect these settings.
  555. N.B. PopPolicyLock must be held.
  556. Arguments:
  557. Flags- The flags to set if the level has already been passed:
  558. example: When user changes alarm leve, we don't want clear
  559. PO_TRG_USER|PO_TRG_SYSTEM. If the recalculation was caused by a change
  560. (startup, or AC unplug), we just want to set PO_TRG_SYSTEM because we
  561. still want the user notification.
  562. Return Value:
  563. None.
  564. --*/
  565. {
  566. PSYSTEM_POWER_LEVEL DPolicy;
  567. ULONG i;
  568. //
  569. // Calculate any level settings
  570. //
  571. for (i=0; i < PO_NUM_POWER_LEVELS; i++) {
  572. DPolicy = &PopPolicy->DischargePolicy[i];
  573. //
  574. // If this setting not calculated handle it
  575. //
  576. if (!(PopCB.Trigger[i].Flags & PO_TRG_SET) && DPolicy->Enable) {
  577. //
  578. // Compute battery capacity setting for percentage
  579. //
  580. PopCB.Trigger[i].Flags |= PO_TRG_SET;
  581. PopCB.Trigger[i].Battery.Level =
  582. PopCB.Info.FullChargedCapacity * DPolicy->BatteryLevel / 100 +
  583. PopCB.Info.FullChargedCapacity / 200;
  584. //
  585. // Make sure setting is not below the lowest default
  586. //
  587. if (PopCB.Trigger[i].Battery.Level < PopCB.Info.DefaultAlert1) {
  588. PopCB.Trigger[i].Battery.Level = PopCB.Info.DefaultAlert1;
  589. }
  590. //
  591. // Skip system action if battery capacity was already below level.
  592. // This will occur on startup, when a battery is changed,
  593. // and when AC comes or goes.
  594. //
  595. if (PopCB.Status.Capacity < PopCB.Trigger[i].Battery.Level) {
  596. PopCB.Trigger[i].Flags |= Flags;
  597. }
  598. }
  599. }
  600. }
  601. VOID
  602. PopComputeCBTime (
  603. VOID
  604. )
  605. /*++
  606. Routine Description:
  607. This function is invoked after the battery status & estimated time
  608. have been read from the battery. This function can apply heuristics
  609. or other knowedge to improve the extimated time.
  610. N.B. PopPolicyLock must be held.
  611. Arguments:
  612. None
  613. Return Value:
  614. None.
  615. --*/
  616. {
  617. // for now just use the batteries value
  618. PopCB.AdjustedEstTime = PopCB.EstTime;
  619. }
  620. VOID
  621. PopResetCBTriggers (
  622. IN UCHAR Flags
  623. )
  624. /*++
  625. Routine Description:
  626. This function clears the requested bits from the batteries trigger flags.
  627. N.B. PopPolicyLock must be held.
  628. Arguments:
  629. Flags - Bits to clear
  630. Return Value:
  631. Status
  632. --*/
  633. {
  634. ULONG i;
  635. ASSERT_POLICY_LOCK_OWNED();
  636. //
  637. // Clear flag bits
  638. //
  639. Flags = ~Flags;
  640. for (i=0; i < PO_NUM_POWER_LEVELS; i++) {
  641. PopCB.Trigger[i].Flags &= Flags;
  642. }
  643. //
  644. // Reread battery status
  645. //
  646. if (PopCB.StatusIrp) {
  647. IoCancelIrp (PopCB.StatusIrp);
  648. }
  649. }
  650. NTSTATUS
  651. PopCurrentPowerState (
  652. OUT PSYSTEM_BATTERY_STATE PowerState
  653. )
  654. /*++
  655. Routine Description:
  656. This function returns the current system power state. If needed,
  657. this function will cause the composite battery irp to get the
  658. current battery status.
  659. N.B. PopPolicyLock must be held.
  660. N.B. The function may drop the PopPolicyLock
  661. Arguments:
  662. PowerState - The current power state
  663. Return Value:
  664. Status
  665. --*/
  666. {
  667. ULONGLONG CurrentTime;
  668. NTSTATUS Status;
  669. ASSERT_POLICY_LOCK_OWNED();
  670. Status = STATUS_SUCCESS;
  671. RtlZeroMemory (PowerState, sizeof(SYSTEM_BATTERY_STATE));
  672. //
  673. // Wait for valid state in PopCB
  674. //
  675. do {
  676. //
  677. // If there's not a composite battery, then return
  678. //
  679. if (PopCB.State == PO_CB_NONE || PopCB.State == PO_CB_WAIT_TAG) {
  680. PowerState->AcOnLine = PopPolicy == &PopAcPolicy;
  681. // Indicate no battery found...
  682. PERFINFO_POWER_BATTERY_LIFE_INFO(-1, 0);
  683. return STATUS_SUCCESS;
  684. }
  685. //
  686. // If device state not being read, we need to wait
  687. //
  688. if (PopCB.State == PO_CB_READ_STATUS) {
  689. //
  690. // If last EstTime was calculated within PO_MAX_CB_CACHE_TIME,
  691. // use the current data. (note this implies status was sucessfully
  692. // read just before time was calcualted)
  693. //
  694. CurrentTime = KeQueryInterruptTime();
  695. if (CurrentTime - PopCB.EstTimeTime < PO_MAX_CB_CACHE_TIME) {
  696. break;
  697. }
  698. }
  699. //
  700. // Need new status. If no other threads are waiting for
  701. // system power state, then setup for wait
  702. //
  703. if (!PopCB.ThreadWaiting) {
  704. PopCB.ThreadWaiting = TRUE;
  705. KeResetEvent (&PopCB.Event);
  706. //
  707. // If read status is in progress, cancel it so we
  708. // can read status now
  709. //
  710. if (PopCB.State == PO_CB_READ_STATUS) {
  711. IoCancelIrp (PopCB.StatusIrp);
  712. }
  713. }
  714. //
  715. // Wait for status update
  716. //
  717. PopReleasePolicyLock (FALSE);
  718. Status = KeWaitForSingleObject (&PopCB.Event, Executive, KernelMode, TRUE, NULL);
  719. PopAcquirePolicyLock ();
  720. } while (NT_SUCCESS(Status));
  721. //
  722. // Generate power state
  723. //
  724. PowerState->AcOnLine = (PopCB.Status.PowerState & BATTERY_POWER_ON_LINE) ? TRUE : FALSE;
  725. PowerState->BatteryPresent = TRUE;
  726. PowerState->Charging = (PopCB.Status.PowerState & BATTERY_CHARGING) ? TRUE : FALSE;
  727. PowerState->Discharging = (PopCB.Status.PowerState & BATTERY_DISCHARGING) ? TRUE : FALSE;
  728. PowerState->MaxCapacity = PopCB.Info.FullChargedCapacity;
  729. PowerState->RemainingCapacity = PopCB.Status.Capacity;
  730. PowerState->Rate = PopCB.Status.Current;
  731. PowerState->EstimatedTime = PopCB.AdjustedEstTime;
  732. PowerState->DefaultAlert1 = PopCB.Info.DefaultAlert1;
  733. PowerState->DefaultAlert2 = PopCB.Info.DefaultAlert2;
  734. PERFINFO_POWER_BATTERY_LIFE_INFO(PowerState->RemainingCapacity, PowerState->Rate);
  735. return Status;
  736. }