From 22bb1901b6aaed7fb66ad8bf67c7dd42d5b333d2 Mon Sep 17 00:00:00 2001 From: Sir Richard Date: Sun, 21 Mar 2010 18:04:08 +0000 Subject: [PATCH] [CMBATT]: Implement CmBattQueryTag and CmBattNotifyHandler for getting ACPI Battery notifications, as per ACPI Spec and http://www.microsoft.com/whdc/archive/ACPInotify.mspx. svn path=/trunk/; revision=46309 --- reactos/drivers/bus/acpi/cmbatt/cmbatt.c | 171 ++++++++++++++++++++++- reactos/drivers/bus/acpi/cmbatt/cmbatt.h | 26 +++- 2 files changed, 187 insertions(+), 10 deletions(-) diff --git a/reactos/drivers/bus/acpi/cmbatt/cmbatt.c b/reactos/drivers/bus/acpi/cmbatt/cmbatt.c index 45903cb16e0..2b69d27effc 100644 --- a/reactos/drivers/bus/acpi/cmbatt/cmbatt.c +++ b/reactos/drivers/bus/acpi/cmbatt/cmbatt.c @@ -43,10 +43,117 @@ CmBattWakeDpc(PKDPC Dpc, 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 = 0xFFFFFFFF; + + /* 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 @@ -156,11 +263,61 @@ CmBattIoctl(PDEVICE_OBJECT DeviceObject, 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 = 0xFFFFFFFF; + + /* 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 diff --git a/reactos/drivers/bus/acpi/cmbatt/cmbatt.h b/reactos/drivers/bus/acpi/cmbatt/cmbatt.h index 34e580d1a23..1ce38bd4d47 100644 --- a/reactos/drivers/bus/acpi/cmbatt/cmbatt.h +++ b/reactos/drivers/bus/acpi/cmbatt/cmbatt.h @@ -29,6 +29,15 @@ typedef enum _CMBATT_EXTENSION_TYPE CmBattBattery } CMBATT_EXTENSION_TYPE; +#define ACPI_BUS_CHECK 0x00 +#define ACPI_DEVICE_CHECK 0x01 + +#define ACPI_STA_PRESENT 0x01 +#define ACPI_STA_ENABLED 0x02 +#define ACPI_STA_SHOW_UI 0x04 +#define ACPI_STA_FUNCTIONAL 0x08 +#define ACPI_STA_BATTERY_PRESENT 0x10 + #define ACPI_BATT_NOTIFY_STATUS 0x80 #define ACPI_BATT_NOTIFY_INFO 0x81 @@ -67,6 +76,10 @@ typedef struct _ACPI_BIF_DATA CHAR OemInfo[256]; } ACPI_BIF_DATA, *PACPI_BIF_DATA; +#define CMBATT_AR_NOTIFY 0x01 +#define CMBATT_AR_INSERT 0x02 +#define CMBATT_AR_REMOVE 0x04 + typedef struct _CMBATT_DEVICE_EXTENSION { CMBATT_EXTENSION_TYPE FdoType; @@ -85,11 +98,11 @@ typedef struct _CMBATT_DEVICE_EXTENSION ULONG DeviceId; PUNICODE_STRING DeviceName; ACPI_INTERFACE_STANDARD2 AcpiInterface; - BOOLEAN DelayAr; - BOOLEAN DelayedArFlag; + BOOLEAN DelayNotification; + BOOLEAN ArFlag; PVOID ClassData; BOOLEAN Started; - BOOLEAN DelayNotification; + BOOLEAN NotifySent; LONG ArLockValue; ULONG TagData; ULONG Tag; @@ -157,4 +170,11 @@ CmBattGetPsrData( PULONG PsrData ); +NTSTATUS +NTAPI +CmBattGetStaData( + PDEVICE_OBJECT DeviceObject, + PULONG StaData +); + /* EOF */ -- 2.17.1