UNICODE_STRING GlobalRegistryPath;
KTIMER CmBattWakeDpcTimerObject;
KDPC CmBattWakeDpcObject;
+PDEVICE_OBJECT AcAdapterPdo;
+LARGE_INTEGER CmBattWakeDpcDelay;
/* FUNCTIONS ******************************************************************/
VOID
NTAPI
-CmBattPowerCallBack(PCMBATT_DEVICE_EXTENSION DeviceExtension,
- PVOID Argument1,
- PVOID Argument2)
+CmBattPowerCallBack(IN PCMBATT_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG Action,
+ IN ULONG Value)
{
- UNIMPLEMENTED;
+ BOOLEAN Cancelled;
+ PDEVICE_OBJECT DeviceObject;
+ if (CmBattDebug & 0x10)
+ DbgPrint("CmBattPowerCallBack: action: %d, value: %d \n", Action, Value);
+
+ /* Check if a transition is going to happen */
+ if (Action == PO_CB_SYSTEM_STATE_LOCK)
+ {
+ /* We have just re-entered S0: call the wake DPC in 10 seconds */
+ if (Value == 0)
+ {
+ if (CmBattDebug & 0x10)
+ DbgPrint("CmBattPowerCallBack: Calling CmBattWakeDpc after 10 seconds.\n");
+ Cancelled = KeSetTimer(&CmBattWakeDpcTimerObject, CmBattWakeDpcDelay, &CmBattWakeDpcObject);
+ if (CmBattDebug & 0x10)
+ DbgPrint("CmBattPowerCallBack: timerCanceled = %d.\n", Cancelled);
+ }
+ else if (Value == 0)
+ {
+ /* We are exiting the S0 state: loop all devices to set the delay flag */
+ if (CmBattDebug & 0x10)
+ DbgPrint("CmBattPowerCallBack: Delaying Notifications\n");
+ for (DeviceObject = DeviceExtension->DeviceObject;
+ DeviceObject;
+ DeviceObject = DeviceObject->NextDevice)
+ {
+ /* Set the delay flag */
+ DeviceExtension = DeviceObject->DeviceExtension;
+ DeviceExtension->DelayNotification = TRUE;
+ }
+ }
+ else if (CmBattDebug & 0x10)
+ {
+ /* Unknown value */
+ DbgPrint("CmBattPowerCallBack: unknown argument2 = %08x\n");
+ }
+ }
}
VOID
NTAPI
-CmBattWakeDpc(PKDPC Dpc,
- PCMBATT_DEVICE_EXTENSION FdoExtension,
- PVOID SystemArgument1,
- PVOID SystemArgument2)
+CmBattWakeDpc(IN PKDPC Dpc,
+ IN PCMBATT_DEVICE_EXTENSION FdoExtension,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2)
{
+ PDEVICE_OBJECT CurrentObject;
+ BOOLEAN AcNotify = FALSE;
+ PCMBATT_DEVICE_EXTENSION DeviceExtension;
+ ULONG ArFlag;
+ if (CmBattDebug & 2) DbgPrint("CmBattWakeDpc: Entered.\n");
+
+ /* Loop all device objects */
+ for (CurrentObject = FdoExtension->DeviceObject;
+ CurrentObject;
+ CurrentObject = CurrentObject->NextDevice)
+ {
+ /* Turn delay flag off, we're back in S0 */
+ DeviceExtension = CurrentObject->DeviceExtension;
+ DeviceExtension->DelayNotification = 0;
+
+ /* Check if this is an AC adapter */
+ if (DeviceExtension->FdoType == CmBattAcAdapter)
+ {
+ /* Was there a pending notify? */
+ if (DeviceExtension->ArFlag & CMBATT_AR_NOTIFY)
+ {
+ /* We'll send a notify on the next pass */
+ AcNotify = TRUE;
+ DeviceExtension->ArFlag = 0;
+ if (CmBattDebug & 0x20)
+ DbgPrint("CmBattWakeDpc: AC adapter notified\n");
+ }
+ }
+ }
+
+ /* Loop the device objects again */
+ for (CurrentObject = FdoExtension->DeviceObject;
+ CurrentObject;
+ CurrentObject = CurrentObject->NextDevice)
+ {
+ /* Check if this is a battery */
+ DeviceExtension = CurrentObject->DeviceExtension;
+ if (DeviceExtension->FdoType == CmBattBattery)
+ {
+ /* Check what ARs are pending */
+ ArFlag = DeviceExtension->ArFlag;
+ if (CmBattDebug & 0x20)
+ DbgPrint("CmBattWakeDpc: Performing delayed ARs: %01x\n", ArFlag);
+ /* Insert notification, clear the lock value */
+ if (ArFlag & CMBATT_AR_INSERT) InterlockedExchange(&DeviceExtension->ArLockValue, 0);
+
+ /* Removal, clear the battery tag */
+ if (ArFlag & CMBATT_AR_REMOVE) DeviceExtension->Tag = 0;
+
+ /* Notification (or AC/DC adapter change from first pass above) */
+ if ((ArFlag & CMBATT_AR_NOTIFY) || (AcNotify))
+ {
+ /* Notify the class driver */
+ BatteryClassStatusNotify(DeviceExtension->ClassData);
+ }
+ }
+ }
}
VOID
NTAPI
-CmBattNotifyHandler(PCMBATT_DEVICE_EXTENSION DeviceExtension,
- ULONG NotifyValue)
+CmBattNotifyHandler(IN PCMBATT_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG NotifyValue)
{
- UNIMPLEMENTED;
+ ULONG ArFlag;
+ PCMBATT_DEVICE_EXTENSION FdoExtension;
+ PDEVICE_OBJECT DeviceObject;
+
+ if (CmBattDebug & (CMBATT_ACPI_ASSERT | CMBATT_PNP_INFO))
+ DbgPrint("CmBattNotifyHandler: CmBatt 0x%08x Type %d Number %d Notify Value: %x\n",
+ DeviceExtension,
+ DeviceExtension->FdoType,
+ DeviceExtension->DeviceId,
+ NotifyValue);
+
+ /* Check what kind of notification was received */
+ switch (NotifyValue)
+ {
+ /* ACPI Specification says is sends a "Bus Check" when power source changes */
+ case ACPI_BUS_CHECK:
+
+ /* We treat it as possible physical change */
+ DeviceExtension->ArFlag |= (CMBATT_AR_NOTIFY | CMBATT_AR_INSERT);
+ if ((DeviceExtension->Tag) &&
+ (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING)))
+ DbgPrint("CmBattNotifyHandler: Received battery #%x insertion, but tag was not invalid.\n",
+ DeviceExtension->DeviceId);
+ break;
+
+ /* Status of the battery has changed */
+ case ACPI_BATT_NOTIFY_STATUS:
+
+ /* All we'll do is notify the class driver */
+ DeviceExtension->ArFlag |= CMBATT_AR_NOTIFY;
+ break;
+
+ /* Information on the battery has changed, such as physical presence */
+ case ACPI_DEVICE_CHECK:
+ case ACPI_BATT_NOTIFY_INFO:
+
+ /* Reset all state and let the class driver re-evaluate it all */
+ DeviceExtension->ArFlag |= (CMBATT_AR_NOTIFY |
+ CMBATT_AR_INSERT |
+ CMBATT_AR_REMOVE);
+ break;
+
+ default:
+
+ if (CmBattDebug & CMBATT_PNP_INFO)
+ DbgPrint("CmBattNotifyHandler: Unknown Notify Value: %x\n", NotifyValue);
+ }
+
+ /* Check if we're supposed to delay the notification till later */
+ if (DeviceExtension->DelayNotification)
+ {
+ /* We'll handle this when we get a status query later on */
+ if (CmBattDebug & CMBATT_PNP_INFO)
+ DbgPrint("CmBattNotifyHandler: Notification delayed: ARs = %01x\n",
+ DeviceExtension->ArFlag);
+ return;
+ }
+
+ /* We're going to handle this now */
+ if (CmBattDebug & CMBATT_PNP_INFO)
+ DbgPrint("CmBattNotifyHandler: Performing ARs: %01x\n", DeviceExtension->ArFlag);
+
+ /* Check if this is a battery or AC adapter notification */
+ if (DeviceExtension->FdoType == CmBattBattery)
+ {
+ /* Reset the current trip point */
+ DeviceExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY;
+
+ /* Check what ARs have to be done */
+ ArFlag = DeviceExtension->ArFlag;
+
+ /* New battery inserted, reset lock value */
+ if (ArFlag & CMBATT_AR_INSERT) InterlockedExchange(&DeviceExtension->ArLockValue, 0);
+
+ /* Check if the battery may have been removed */
+ if (ArFlag & CMBATT_AR_REMOVE) DeviceExtension->Tag = 0;
+
+ /* Check if there's been any sort of change to the battery */
+ if (ArFlag & CMBATT_AR_NOTIFY)
+ {
+ /* We'll probably end up re-evaluating _BIF and _BST */
+ DeviceExtension->NotifySent = TRUE;
+ BatteryClassStatusNotify(DeviceExtension->ClassData);
+ }
+ }
+ else
+ {
+ /* The only known notification is AC/DC change */
+ if (DeviceExtension->ArFlag & CMBATT_AR_NOTIFY)
+ {
+ for (DeviceObject = DeviceExtension->FdoDeviceObject->DriverObject->DeviceObject;
+ DeviceObject;
+ DeviceObject = DeviceObject->NextDevice)
+ {
+ /* Is this a battery? */
+ FdoExtension = DeviceObject->DeviceExtension;
+ if (FdoExtension->FdoType == CmBattBattery)
+ {
+ /* Send a notification to the class driver */
+ FdoExtension->NotifySent = TRUE;
+ BatteryClassStatusNotify(FdoExtension->ClassData);
+ }
+ }
+ }
+ }
+
+ /* ARs have been processed */
+ DeviceExtension->ArFlag = 0;
}
VOID
NTSTATUS
NTAPI
-CmBattQueryTag(PCMBATT_DEVICE_EXTENSION DeviceExtension,
- PULONG BatteryTag)
+CmBattQueryTag(IN PCMBATT_DEVICE_EXTENSION DeviceExtension,
+ OUT PULONG Tag)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ PDEVICE_OBJECT PdoDevice;
+ ULONG StaData;
+ ULONG NewTag;
+ NTSTATUS Status;
+ PAGED_CODE();
+ if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO))
+ DbgPrint("CmBattQueryTag - Tag (%d), Battery %x, Device %d\n",
+ *Tag, DeviceExtension, DeviceExtension->DeviceId);
+
+ /* Get PDO and clear notification flag */
+ PdoDevice = DeviceExtension->PdoDeviceObject;
+ DeviceExtension->NotifySent = 0;
+
+ /* Get _STA from PDO (we need the machine status, not the battery status) */
+ Status = CmBattGetStaData(PdoDevice, &StaData);
+ if (NT_SUCCESS(Status))
+ {
+ /* Is a battery present? */
+ if (StaData & ACPI_STA_BATTERY_PRESENT)
+ {
+ /* Do we not have a tag yet? */
+ if (!DeviceExtension->Tag)
+ {
+ /* Set the new tag value, reset tags if we reached the maximum */
+ NewTag = DeviceExtension->TagData;
+ if (DeviceExtension->TagData++ == 0xFFFFFFFF) NewTag = 1;
+ DeviceExtension->Tag = NewTag;
+ if (CmBattDebug & CMBATT_GENERIC_INFO)
+ DbgPrint("CmBattQueryTag - New Tag: (%d)\n", DeviceExtension->Tag);
+
+ /* Reset trip point data */
+ DeviceExtension->TripPointOld = 0;
+ DeviceExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY;
+
+ /* Clear AR lock and set new interrupt time */
+ InterlockedExchange(&DeviceExtension->ArLockValue, 0);
+ DeviceExtension->InterruptTime = KeQueryInterruptTime();
+ }
+ }
+ else
+ {
+ /* No battery, so no tag */
+ DeviceExtension->Tag = 0;
+ Status = STATUS_NO_SUCH_DEVICE;
+ }
+ }
+
+ /* Return the tag and status result */
+ *Tag = DeviceExtension->Tag;
+ if (CmBattDebug & CMBATT_ACPI_WARNING)
+ DbgPrint("CmBattQueryTag: Returning Tag: 0x%x, status 0x%x\n", *Tag, Status);
+ return Status;
}
NTSTATUS
NTAPI
-CmBattDisableStatusNotify(PCMBATT_DEVICE_EXTENSION DeviceExtension)
+CmBattDisableStatusNotify(IN PCMBATT_DEVICE_EXTENSION DeviceExtension)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ NTSTATUS Status;
+ PAGED_CODE();
+ if (CmBattDebug & 0xA) DbgPrint("CmBattDisableStatusNotify\n");
+
+ /* Do we have a trip point */
+ if (DeviceExtension->TripPointSet)
+ {
+ /* Is there a current value set? */
+ if (DeviceExtension->TripPointValue)
+ {
+ /* Reset it back to 0 */
+ DeviceExtension->TripPointValue = 0;
+ Status = CmBattSetTripPpoint(DeviceExtension, 0);
+ if (!NT_SUCCESS(Status))
+ {
+ /* If it failed, set unknown/invalid value */
+ DeviceExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY;
+ if (CmBattDebug & 8)
+ DbgPrint("CmBattDisableStatusNotify: SetTripPoint failed - %x\n", Status);
+ }
+ }
+ else
+ {
+ /* No trip point set, so this is a successful no-op */
+ Status = STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ /* Nothing we can do */
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ /* Return status */
+ return Status;
}
NTSTATUS
NTAPI
-CmBattSetStatusNotify(PCMBATT_DEVICE_EXTENSION DeviceExtension,
- ULONG BatteryTag,
- PBATTERY_NOTIFY BatteryNotify)
+CmBattSetStatusNotify(IN PCMBATT_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG BatteryTag,
+ IN PBATTERY_NOTIFY BatteryNotify)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ NTSTATUS Status;
+ ACPI_BST_DATA BstData;
+ ULONG Capacity, NewTripPoint, TripPoint, DesignVoltage;
+ BOOLEAN Charging;
+ PAGED_CODE();
+ if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO))
+ DbgPrint("CmBattSetStatusNotify: Tag (%d) Target(0x%x)\n",
+ BatteryTag, BatteryNotify->LowCapacity);
+
+ /* Update any ACPI evaluations */
+ Status = CmBattVerifyStaticInfo(DeviceExtension, BatteryTag);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Trip point not supported, fail */
+ if (!DeviceExtension->TripPointSet) return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ /* Are both capacities known? */
+ if ((BatteryNotify->HighCapacity == BATTERY_UNKNOWN_CAPACITY) ||
+ (BatteryNotify->LowCapacity == BATTERY_UNKNOWN_CAPACITY))
+ {
+ /* We can't set trip points without these */
+ if (CmBattDebug & CMBATT_GENERIC_WARNING)
+ DbgPrint("CmBattSetStatusNotify: Failing request because of BATTERY_UNKNOWN_CAPACITY.\n");
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ /* Is the battery charging? */
+ Charging = DeviceExtension->BstData.State & ACPI_BATT_STAT_CHARGING;
+ if (Charging)
+ {
+ /* Then the trip point is when we hit the cap */
+ Capacity = BatteryNotify->HighCapacity;
+ NewTripPoint = BatteryNotify->HighCapacity;
+ }
+ else
+ {
+ /* Otherwise it's when we discharge to the bottom */
+ Capacity = BatteryNotify->LowCapacity;
+ NewTripPoint = BatteryNotify->LowCapacity;
+ }
+
+ /* Do we have data in Amps or Watts? */
+ if (DeviceExtension->BifData.PowerUnit == ACPI_BATT_POWER_UNIT_AMPS)
+ {
+ /* We need the voltage to do the conversion */
+ DesignVoltage = DeviceExtension->BifData.DesignVoltage;
+ if ((DesignVoltage != BATTERY_UNKNOWN_VOLTAGE) && (DesignVoltage))
+ {
+ /* Convert from mAh into Ah */
+ TripPoint = 1000 * NewTripPoint;
+ if (Charging)
+ {
+ /* Scale the high trip point */
+ NewTripPoint = (TripPoint + 500) / DesignVoltage + ((TripPoint + 500) % DesignVoltage != 0);
+ }
+ else
+ {
+ /* Scale the low trip point */
+ NewTripPoint = (TripPoint - 500) / DesignVoltage - ((TripPoint - 500) % DesignVoltage == 0);
+ }
+ }
+ else
+ {
+ /* Without knowing the voltage, Amps are not enough data on consumption */
+ Status = STATUS_NOT_SUPPORTED;
+ if (CmBattDebug & CMBATT_ACPI_WARNING)
+ DbgPrint("CmBattSetStatusNotify: Can't calculate BTP, DesignVoltage = 0x%08x\n",
+ DesignVoltage);
+ }
+ }
+ else if (Charging)
+ {
+ /* Make it trip just one past the charge cap */
+ ++NewTripPoint;
+ }
+ else if (NewTripPoint > 0)
+ {
+ /* Make it trip just one below the drain cap */
+ --NewTripPoint;
+ }
+
+ /* Do we actually have a new trip point? */
+ if (NewTripPoint == DeviceExtension->TripPointValue)
+ {
+ /* No, so there is no work to be done */
+ if (CmBattDebug & CMBATT_GENERIC_STATUS)
+ DbgPrint("CmBattSetStatusNotify: Keeping original setting: %X\n", DeviceExtension->TripPointValue);
+ return STATUS_SUCCESS;
+ }
+
+ /* Set the trip point with ACPI and check for success */
+ DeviceExtension->TripPointValue = NewTripPoint;
+ Status = CmBattSetTripPpoint(DeviceExtension, NewTripPoint);
+ if (!(NewTripPoint) && (Capacity)) Status = STATUS_NOT_SUPPORTED;
+ if (!NT_SUCCESS(Status))
+ {
+ /* We failed to set the trip point, or there wasn't one settable */
+ DeviceExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY;
+ if (CmBattDebug & (CMBATT_GENERIC_WARNING | CMBATT_ACPI_WARNING))
+ DbgPrint("CmBattSetStatusNotify: SetTripPoint failed - %x\n", Status);
+ return Status;
+ }
+
+ /* Read the new BST data to see the latest state */
+ Status = CmBattGetBstData(DeviceExtension, &BstData);
+ if (!NT_SUCCESS(Status))
+ {
+ /* We'll return failure to the caller */
+ if (CmBattDebug & (CMBATT_GENERIC_WARNING | CMBATT_ACPI_WARNING))
+ DbgPrint("CmBattSetStatusNotify: GetBstData - %x\n", Status);
+ }
+ else if ((Charging) && (BstData.RemainingCapacity >= NewTripPoint))
+ {
+ /* We are charging and our capacity is past the trip point, so trip now */
+ if (CmBattDebug & CMBATT_GENERIC_WARNING)
+ DbgPrint("CmBattSetStatusNotify: Trip point already crossed (1): TP = %08x, remaining capacity = %08x\n",
+ NewTripPoint, BstData.RemainingCapacity);
+ CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS);
+ }
+ else if ((BstData.RemainingCapacity) && (Capacity))
+ {
+ /* We are discharging, and our capacity is below the trip point, trip now */
+ if (CmBattDebug & CMBATT_GENERIC_WARNING)
+ DbgPrint("CmBattSetStatusNotify: Trip point already crossed (1): TP = %08x, remaining capacity = %08x\n",
+ NewTripPoint, BstData.RemainingCapacity);
+ CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS);
+ }
+
+ /* All should've went well if we got here, unless BST failed... return! */
+ if (CmBattDebug & CMBATT_GENERIC_STATUS)
+ DbgPrint("CmBattSetStatusNotify: Want %X CurrentCap %X\n",
+ Capacity, DeviceExtension->RemainingCapacity);
+ if (CmBattDebug & CMBATT_ACPI_WARNING)
+ DbgPrint("CmBattSetStatusNotify: Set to: [%#08lx][%#08lx][%#08lx] Status %x\n",
+ BatteryNotify->PowerState,
+ BatteryNotify->LowCapacity,
+ BatteryNotify->HighCapacity);
+ return Status;
}
NTSTATUS
NTAPI
-CmBattGetBatteryStatus(PCMBATT_DEVICE_EXTENSION DeviceExtension,
- ULONG BatteryTag)
+CmBattGetBatteryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension,
+ IN ULONG Tag)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ 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
RegistryPath->Buffer);
/* Setup the major dispatchers */
- DriverObject->MajorFunction[0] = CmBattOpenClose;
- DriverObject->MajorFunction[2] = CmBattOpenClose;
- DriverObject->MajorFunction[14] = CmBattIoctl;
- DriverObject->MajorFunction[22] = CmBattPowerDispatch;
- DriverObject->MajorFunction[27] = CmBattPnpDispatch;
- DriverObject->MajorFunction[23] = CmBattSystemControl;
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = CmBattOpenClose;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = CmBattOpenClose;
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CmBattIoctl;
+ DriverObject->MajorFunction[IRP_MJ_POWER] = CmBattPowerDispatch;
+ DriverObject->MajorFunction[IRP_MJ_PNP] = CmBattPnpDispatch;
+ DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = CmBattSystemControl;
/* And the unload routine */
DriverObject->DriverUnload = CmBattUnload;