341 lines
8.8 KiB
C
341 lines
8.8 KiB
C
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cmhndlr.c
|
|
|
|
Abstract:
|
|
|
|
Control Method Battery handlers
|
|
|
|
Author:
|
|
|
|
Bob Moore
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "CmBattp.h"
|
|
|
|
|
|
VOID
|
|
CmBattPowerCallBack(
|
|
IN PVOID CallBackContext,
|
|
IN PVOID Argument1,
|
|
IN PVOID Argument2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called when the system changes power states
|
|
|
|
Arguments:
|
|
|
|
CallBackContext - The device extension for the root device
|
|
Argument1
|
|
|
|
--*/
|
|
{
|
|
|
|
PDRIVER_OBJECT CmBattDriver = (PDRIVER_OBJECT) CallBackContext;
|
|
ULONG action = PtrToUlong( Argument1 );
|
|
ULONG value = PtrToUlong( Argument2 );
|
|
BOOLEAN timerCanceled;
|
|
PDEVICE_OBJECT CmBattDevice;
|
|
PCM_BATT CmBatt;
|
|
|
|
CmBattPrint (CMBATT_POWER, ("CmBattPowerCallBack: action: %d, value: %d \n", action, value));
|
|
|
|
//
|
|
// We are looking for a PO_CB_SYSTEM_STATE_LOCK
|
|
//
|
|
if (action != PO_CB_SYSTEM_STATE_LOCK) {
|
|
return;
|
|
}
|
|
|
|
switch (value) {
|
|
case 0:
|
|
CmBattPrint (CMBATT_POWER, ("CmBattPowerCallBack: Delaying Notifications\n"));
|
|
//
|
|
// Get the head of the DeviceObject list
|
|
//
|
|
|
|
CmBattDevice = CmBattDriver->DeviceObject;
|
|
|
|
while (CmBattDevice) {
|
|
CmBatt = CmBattDevice->DeviceExtension;
|
|
|
|
//
|
|
// Cause all notifications to be delayed.
|
|
//
|
|
CmBatt->Sleeping = TRUE;
|
|
|
|
CmBattDevice = CmBattDevice->NextDevice;
|
|
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
CmBattPrint (CMBATT_POWER, ("CmBattPowerCallBack: Calling CmBattWakeDpc after 10 seconds.\n"));
|
|
timerCanceled = KeSetTimer (&CmBattWakeDpcTimerObject,
|
|
CmBattWakeDpcDelay,
|
|
&CmBattWakeDpcObject);
|
|
CmBattPrint (CMBATT_POWER, ("CmBattPowerCallBack: timerCanceled = %d.\n", timerCanceled));
|
|
break;
|
|
|
|
default:
|
|
CmBattPrint (CMBATT_POWER, ("CmBattPowerCallBack: unknown argument2 = %08x\n", value));
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
CmBattWakeDpc (
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called X seconds after the system wakes to proces
|
|
all delayed battery notifications.
|
|
|
|
Arguments:
|
|
|
|
CmBattDriver - Driver object
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PDRIVER_OBJECT CmBattDriver = (PDRIVER_OBJECT) DeferredContext;
|
|
BOOLEAN notifyAll = FALSE;
|
|
PDEVICE_OBJECT CmBattDevice;
|
|
PCM_BATT CmBatt;
|
|
|
|
CmBattPrint (CMBATT_TRACE, ("CmBattWakeDpc: Entered.\n"));
|
|
//
|
|
// Get the head of the DeviceObject list
|
|
//
|
|
|
|
CmBattDevice = CmBattDriver->DeviceObject;
|
|
|
|
while (CmBattDevice) {
|
|
CmBatt = CmBattDevice->DeviceExtension;
|
|
|
|
//
|
|
// We will now process all delayed notifications.
|
|
// For effeiciency, we must go through the devices twice:
|
|
// first to see if any AC devices have been notified, and
|
|
// then to send notifications to all battery devices if necessary.
|
|
//
|
|
CmBatt->Sleeping = FALSE;
|
|
|
|
if ((CmBatt->Type == AC_ADAPTER_TYPE) &&
|
|
(CmBatt->ActionRequired & CMBATT_AR_NOTIFY)) {
|
|
|
|
//
|
|
// If any AC adapter devices have notified,
|
|
// then we need to notify all battery devices
|
|
//
|
|
CmBattPrint (CMBATT_PNP, ("CmBattWakeDpc: AC adapter notified\n"));
|
|
notifyAll = TRUE;
|
|
CmBatt->ActionRequired = CMBATT_AR_NO_ACTION;
|
|
}
|
|
|
|
CmBattDevice = CmBattDevice->NextDevice;
|
|
|
|
}
|
|
|
|
//
|
|
// Get the head of the DeviceObject list
|
|
//
|
|
|
|
CmBattDevice = CmBattDriver->DeviceObject;
|
|
|
|
// Walk the list
|
|
while (CmBattDevice) {
|
|
CmBatt = CmBattDevice->DeviceExtension;
|
|
|
|
if (CmBatt->Type == CM_BATTERY_TYPE) {
|
|
CmBattPrint (CMBATT_PNP, ("CmBattWakeDpc: Performing delayed ARs: %01x\n", CmBatt->ActionRequired));
|
|
|
|
if (CmBatt->ActionRequired & CMBATT_AR_INVALIDATE_CACHE) {
|
|
InterlockedExchange (&CmBatt->CacheState, 0);
|
|
}
|
|
if (CmBatt->ActionRequired & CMBATT_AR_INVALIDATE_TAG) {
|
|
CmBatt->Info.Tag = BATTERY_TAG_INVALID;
|
|
}
|
|
if ((CmBatt->ActionRequired & CMBATT_AR_NOTIFY) || notifyAll) {
|
|
BatteryClassStatusNotify (CmBatt->Class);
|
|
}
|
|
}
|
|
|
|
CmBattDevice = CmBattDevice->NextDevice;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
VOID
|
|
CmBattNotifyHandler (
|
|
IN PVOID Context,
|
|
IN ULONG NotifyValue
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine fields battery device notifications from the ACPI driver.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PCM_BATT CmBatt = Context;
|
|
PDRIVER_OBJECT CmBatteryDriver;
|
|
PDEVICE_OBJECT CmBatteryDevice;
|
|
PCM_BATT CmBatteryExtension;
|
|
|
|
CmBattPrint ((CMBATT_PNP | CMBATT_BIOS), ("CmBattNotifyHandler: CmBatt 0x%08x Type %d Number %d Notify Value: %x\n",
|
|
CmBatt, CmBatt->Type, CmBatt->DeviceNumber, NotifyValue));
|
|
|
|
switch (NotifyValue) {
|
|
|
|
case BATTERY_DEVICE_CHECK:
|
|
//
|
|
// A new battery was inserted in the system.
|
|
//
|
|
|
|
CmBatt->ActionRequired |= CMBATT_AR_NOTIFY;
|
|
CmBatt->ActionRequired |= CMBATT_AR_INVALIDATE_CACHE;
|
|
|
|
//
|
|
// This notification is only received when a battery is inserted.
|
|
// It also occurs after restart from hibernation on some machines.
|
|
// Invalidate battery tag.
|
|
//
|
|
|
|
if (CmBatt->Info.Tag != BATTERY_TAG_INVALID) {
|
|
CmBattPrint ((CMBATT_ERROR),
|
|
("CmBattNotifyHandler: Received battery #%x insertion, but tag was not invalid.\n",
|
|
CmBatt->DeviceNumber));
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case BATTERY_EJECT:
|
|
//
|
|
// A battery was removed from the system
|
|
//
|
|
|
|
CmBatt->ActionRequired |= CMBATT_AR_NOTIFY;
|
|
|
|
//
|
|
// Invalidate the battery tag and all cached informaion
|
|
// whenever this message is received.
|
|
//
|
|
CmBatt->ActionRequired |= CMBATT_AR_INVALIDATE_CACHE;
|
|
CmBatt->ActionRequired |= CMBATT_AR_INVALIDATE_TAG;
|
|
|
|
break;
|
|
|
|
case BATTERY_STATUS_CHANGE: // Status change only
|
|
CmBatt->ActionRequired |= CMBATT_AR_NOTIFY;
|
|
|
|
break;
|
|
|
|
case BATTERY_INFO_CHANGE: // Info & status change
|
|
CmBatt->ActionRequired |= CMBATT_AR_NOTIFY;
|
|
CmBatt->ActionRequired |= CMBATT_AR_INVALIDATE_CACHE;
|
|
CmBatt->ActionRequired |= CMBATT_AR_INVALIDATE_TAG;
|
|
break;
|
|
|
|
default:
|
|
|
|
CmBattPrint (CMBATT_PNP, ("CmBattNotifyHandler: Unknown Notify Value: %x\n", NotifyValue));
|
|
break;
|
|
|
|
}
|
|
|
|
if (CmBatt->Sleeping) {
|
|
CmBattPrint (CMBATT_PNP, ("CmBattNotifyHandler: Notification delayed: ARs = %01x\n", CmBatt->ActionRequired));
|
|
} else {
|
|
CmBattPrint (CMBATT_PNP, ("CmBattNotifyHandler: Performing ARs: %01x\n", CmBatt->ActionRequired));
|
|
if (CmBatt->Type == CM_BATTERY_TYPE) {
|
|
|
|
//
|
|
// Invalidate last trip point set on battery.
|
|
//
|
|
CmBatt->Alarm.Setting = CM_ALARM_INVALID;
|
|
|
|
if (CmBatt->ActionRequired & CMBATT_AR_INVALIDATE_CACHE) {
|
|
InterlockedExchange (&CmBatt->CacheState, 0);
|
|
}
|
|
if (CmBatt->ActionRequired & CMBATT_AR_INVALIDATE_TAG) {
|
|
CmBatt->Info.Tag = BATTERY_TAG_INVALID;
|
|
}
|
|
if (CmBatt->ActionRequired & CMBATT_AR_NOTIFY) {
|
|
CmBatt->ReCheckSta = TRUE;
|
|
BatteryClassStatusNotify (CmBatt->Class);
|
|
}
|
|
|
|
} else if ((CmBatt->Type == AC_ADAPTER_TYPE) &&
|
|
(CmBatt->ActionRequired & CMBATT_AR_NOTIFY)) {
|
|
|
|
//
|
|
// Get the Driver Object
|
|
//
|
|
|
|
CmBatteryDriver = CmBatt->Fdo->DriverObject;
|
|
|
|
//
|
|
// Get the head of the DeviceObject list
|
|
//
|
|
|
|
CmBatteryDevice = CmBatteryDriver->DeviceObject;
|
|
|
|
//
|
|
// Walk the DeviceObject list to notify the class driver on all batteries
|
|
//
|
|
while (CmBatteryDevice) {
|
|
|
|
CmBatteryExtension = CmBatteryDevice->DeviceExtension;
|
|
|
|
if (CmBatteryExtension->Type == CM_BATTERY_TYPE) {
|
|
CmBatteryExtension->ReCheckSta = TRUE;
|
|
BatteryClassStatusNotify (CmBatteryExtension->Class);
|
|
}
|
|
|
|
CmBatteryDevice = CmBatteryDevice->NextDevice;
|
|
}
|
|
}
|
|
|
|
CmBatt->ActionRequired = CMBATT_AR_NO_ACTION;
|
|
}
|
|
}
|
|
|