Author: sir_richard
Date: Sun Mar 21 04:14:12 2010
New Revision: 46291
URL:
http://svn.reactos.org/svn/reactos?rev=46291&view=rev
Log:
[CMBATT]: Implement CmBattGetBatteryStatus. See ACPI Specification 4.0B (10.2 Control
Method Batteries, P.383).
Modified:
trunk/reactos/drivers/bus/acpi/cmbatt/cmbatt.c
trunk/reactos/drivers/bus/acpi/cmbatt/cmbatt.h
Modified: trunk/reactos/drivers/bus/acpi/cmbatt/cmbatt.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/bus/acpi/cmbatt/cm…
==============================================================================
--- trunk/reactos/drivers/bus/acpi/cmbatt/cmbatt.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/bus/acpi/cmbatt/cmbatt.c [iso-8859-1] Sun Mar 21 04:14:12 2010
@@ -18,6 +18,7 @@
UNICODE_STRING GlobalRegistryPath;
KTIMER CmBattWakeDpcTimerObject;
KDPC CmBattWakeDpcObject;
+PDEVICE_OBJECT AcAdapterPdo;
/* FUNCTIONS ******************************************************************/
@@ -182,11 +183,220 @@
NTSTATUS
NTAPI
-CmBattGetBatteryStatus(PCMBATT_DEVICE_EXTENSION DeviceExtension,
- ULONG BatteryTag)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+CmBattGetBatteryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG Tag)
+{
+ ULONG PsrData = 0;
+ NTSTATUS Status;
+ ULONG BstState;
+ ULONG DesignVoltage, PresentRate, RemainingCapacity;
+ PAGED_CODE();
+ if (CmBattDebug & CMBATT_GENERIC_INFO)
+ DbgPrint("CmBattGetBatteryStatus - CmBatt (%08x) Tag (%d)\n",
DeviceExtension, Tag);
+
+ /* Validate ACPI data */
+ Status = CmBattVerifyStaticInfo(DeviceExtension, Tag);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Check for delayed status notifications */
+ if (DeviceExtension->DelayNotification)
+ {
+ /* Process them now and don't do any other work */
+ CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS);
+ return Status;
+ }
+
+ /* Get _BST from ACPI */
+ Status = CmBattGetBstData(DeviceExtension, &DeviceExtension->BstData);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail */
+ InterlockedExchange(&DeviceExtension->ArLockValue, 0);
+ return Status;
+ }
+
+ /* Clear current BST information */
+ DeviceExtension->State = 0;
+ DeviceExtension->RemainingCapacity = 0;
+ DeviceExtension->PresentVoltage = 0;
+ DeviceExtension->Rate = 0;
+
+ /* Get battery state */
+ BstState = DeviceExtension->BstData.State;
+
+ /* Is the battery both charging and discharging? */
+ if ((BstState & ACPI_BATT_STAT_DISCHARG) && (BstState &
ACPI_BATT_STAT_CHARGING) &&
+ (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING)))
+ DbgPrint("************************ ACPI BIOS BUG ********************\n*
"
+ "CmBattGetBatteryStatus: Invalid state: _BST method returned
0x%08x for Battery State.\n"
+ "* One battery cannot be charging and discharging at the same
time.\n",
+ BstState);
+
+ /* Is the battery discharging? */
+ if (BstState & ACPI_BATT_STAT_DISCHARG)
+ {
+ /* Set power state and check if it just started discharging now */
+ DeviceExtension->State |= BATTERY_DISCHARGING;
+ if (!(DeviceExtension->State & ACPI_BATT_STAT_DISCHARG))
+ {
+ /* Remember the time when the state changed */
+ DeviceExtension->InterruptTime = KeQueryInterruptTime();
+ }
+ }
+ else if (BstState & ACPI_BATT_STAT_CHARGING)
+ {
+ /* Battery is charging, update power state */
+ DeviceExtension->State |= (BATTERY_CHARGING | BATTERY_POWER_ON_LINE);
+ }
+
+ /* Is the battery in a critical state? */
+ if (BstState & ACPI_BATT_STAT_CRITICAL) DeviceExtension->State |=
BATTERY_CRITICAL;
+
+ /* Read the voltage data */
+ DeviceExtension->PresentVoltage = DeviceExtension->BstData.PresentVoltage;
+
+ /* Check if we have an A/C adapter */
+ if (AcAdapterPdo)
+ {
+ /* Query information on it */
+ CmBattGetPsrData(AcAdapterPdo, &PsrData);
+ }
+ else
+ {
+ /* Otherwise, check if the battery is charging */
+ if (BstState & ACPI_BATT_STAT_CHARGING)
+ {
+ /* Then we'll assume there's a charger */
+ PsrData = 1;
+ }
+ else
+ {
+ /* Assume no charger */
+ PsrData = 0;
+ }
+ }
+
+ /* Is there a charger? */
+ if (PsrData)
+ {
+ /* Set the power state flag to reflect this */
+ DeviceExtension->State |= BATTERY_POWER_ON_LINE;
+ if (CmBattDebug & (CMBATT_GENERIC_INFO | CMBATT_GENERIC_STATUS))
+ DbgPrint("CmBattGetBatteryStatus: AC adapter is connected\n");
+ }
+ else if (CmBattDebug & (CMBATT_GENERIC_INFO | CMBATT_GENERIC_STATUS))
+ {
+ DbgPrint("CmBattGetBatteryStatus: AC adapter is NOT connected\n");
+ }
+
+ /* Get some data we'll need */
+ DesignVoltage = DeviceExtension->BifData.DesignVoltage;
+ PresentRate = DeviceExtension->BstData.PresentRate;
+ RemainingCapacity = DeviceExtension->BstData.RemainingCapacity;
+
+ /* Check if we have battery data in Watts instead of Amps */
+ if (DeviceExtension->BifData.PowerUnit == ACPI_BATT_POWER_UNIT_WATTS)
+ {
+ /* Get the data from the BST */
+ DeviceExtension->RemainingCapacity = RemainingCapacity;
+ DeviceExtension->Rate = PresentRate;
+
+ /* Check if the rate is invalid */
+ if (PresentRate > CM_MAX_VALUE)
+ {
+ /* Set an unknown rate and don't touch the old value */
+ DeviceExtension->Rate = BATTERY_UNKNOWN_RATE;
+ if ((PresentRate != CM_UNKNOWN_VALUE) && (CmBattDebug &
CMBATT_ACPI_WARNING))
+ {
+ DbgPrint("CmBattGetBatteryStatus - Rate is greater than
CM_MAX_VALUE\n");
+ DbgPrint("---------------------- PresentRate = 0x%08x\n",
PresentRate);
+ }
+ }
+ }
+ else if ((DesignVoltage != CM_UNKNOWN_VALUE) && (DesignVoltage))
+ {
+ /* We have voltage data, what about capacity? */
+ if (RemainingCapacity == CM_UNKNOWN_VALUE)
+ {
+ /* Unable to calculate it */
+ DeviceExtension->RemainingCapacity = BATTERY_UNKNOWN_CAPACITY;
+ if (CmBattDebug & CMBATT_ACPI_WARNING)
+ {
+ DbgPrint("CmBattGetBatteryStatus - Can't calculate
RemainingCapacity \n");
+ DbgPrint("---------------------- RemainingCapacity =
CM_UNKNOWN_VALUE\n");
+ }
+ }
+ else
+ {
+ /* Compute the capacity with the information we have */
+ DeviceExtension->RemainingCapacity = (DesignVoltage * RemainingCapacity +
500) / 1000;
+ }
+
+ /* Check if we have a rate */
+ if (PresentRate != CM_UNKNOWN_VALUE)
+ {
+ /* Make sure the rate isn't too large */
+ if (PresentRate > (-500 / DesignVoltage))
+ {
+ /* It is, so set unknown state */
+ DeviceExtension->Rate = BATTERY_UNKNOWN_RATE;
+ if (CmBattDebug & CMBATT_ACPI_WARNING)
+ {
+ DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate
\n");
+ DbgPrint("---------------------- Overflow: PresentRate =
0x%08x\n", PresentRate);
+ }
+ }
+
+ /* Compute the rate */
+ DeviceExtension->Rate = (PresentRate * DesignVoltage + 500) / 1000;
+ }
+ else
+ {
+ /* We don't have a rate, so set unknown value */
+ DeviceExtension->Rate = BATTERY_UNKNOWN_RATE;
+ if (CmBattDebug & CMBATT_ACPI_WARNING)
+ {
+ DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate
\n");
+ DbgPrint("---------------------- Present Rate =
CM_UNKNOWN_VALUE\n");
+ }
+ }
+ }
+ else
+ {
+ /* We have no rate, and no capacity, set unknown values */
+ DeviceExtension->Rate = BATTERY_UNKNOWN_RATE;
+ DeviceExtension->RemainingCapacity = BATTERY_UNKNOWN_CAPACITY;
+ if (CmBattDebug & CMBATT_ACPI_WARNING)
+ {
+ DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity
and Rate \n");
+ DbgPrint("---------------------- DesignVoltage = 0x%08x\n",
DesignVoltage);
+ }
+ }
+
+ /* Check if we have an unknown rate */
+ if (DeviceExtension->Rate == BATTERY_UNKNOWN_RATE)
+ {
+ /* The battery is discharging but we don't know by how much... this is bad!
*/
+ if ((BstState & ACPI_BATT_STAT_DISCHARG) &&
+ (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING)))
+ DbgPrint("CmBattGetBatteryStatus: battery rate is unkown when battery is
not charging!\n");
+ }
+ else if (DeviceExtension->State & BATTERY_DISCHARGING)
+ {
+ /* The battery is discharging, so treat the rate as a negative rate */
+ DeviceExtension->Rate = -DeviceExtension->Rate;
+ }
+ else if (!(DeviceExtension->State & BATTERY_CHARGING) &&
(DeviceExtension->Rate))
+ {
+ /* We are not charging, not discharging, but have a rate? Ignore it! */
+ if (CmBattDebug & CMBATT_GENERIC_WARNING)
+ DbgPrint("CmBattGetBatteryStatus: battery is not charging or
discharging, but rate = %x\n",
+ DeviceExtension->Rate);
+ DeviceExtension->Rate = 0;
+ }
+
+ /* Done */
+ return STATUS_SUCCESS;
}
NTSTATUS
Modified: trunk/reactos/drivers/bus/acpi/cmbatt/cmbatt.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/bus/acpi/cmbatt/cm…
==============================================================================
--- trunk/reactos/drivers/bus/acpi/cmbatt/cmbatt.h [iso-8859-1] (original)
+++ trunk/reactos/drivers/bus/acpi/cmbatt/cmbatt.h [iso-8859-1] Sun Mar 21 04:14:12 2010
@@ -29,11 +29,15 @@
CmBattBattery
} CMBATT_EXTENSION_TYPE;
+#define ACPI_BATT_NOTIFY_STATUS 0x80
+#define ACPI_BATT_NOTIFY_INFO 0x81
+
#define ACPI_BATT_STAT_DISCHARG 0x0001
#define ACPI_BATT_STAT_CHARGING 0x0002
#define ACPI_BATT_STAT_CRITICAL 0x0004
-#define ACPI_BATT_STAT_NOT_PRESENT 0x0007
-#define ACPI_BATT_STAT_MAX 0x0007
+
+#define CM_MAX_VALUE 0x7FFFFFFF
+#define CM_UNKNOWN_VALUE 0xFFFFFFFF
typedef struct _ACPI_BST_DATA
{
@@ -42,6 +46,9 @@
ULONG RemainingCapacity;
ULONG PresentVoltage;
} ACPI_BST_DATA, *PACPI_BST_DATA;
+
+#define ACPI_BATT_POWER_UNIT_WATTS 0x0
+#define ACPI_BATT_POWER_UNIT_AMPS 0x1
typedef struct _ACPI_BIF_DATA
{
@@ -82,8 +89,8 @@
BOOLEAN DelayedArFlag;
PVOID ClassData;
BOOLEAN Started;
- BOOLEAN NotifySent;
- ULONG ArLock;
+ BOOLEAN DelayNotification;
+ LONG ArLockValue;
ULONG TagData;
ULONG Tag;
ULONG ModelNumberLength;
@@ -135,5 +142,19 @@
PDEVICE_OBJECT DeviceObject,
PIRP Irp
);
-
+
+NTSTATUS
+NTAPI
+CmBattGetBstData(
+ PCMBATT_DEVICE_EXTENSION DeviceExtension,
+ PACPI_BST_DATA BstData
+);
+
+NTSTATUS
+NTAPI
+CmBattGetPsrData(
+ PDEVICE_OBJECT DeviceObject,
+ PULONG PsrData
+);
+
/* EOF */