[CMBATT]: Implement PnP handling. Only the ACPI-facing interface needs to be written...
[reactos.git] / reactos / drivers / bus / acpi / cmbatt / cmbatt.c
index b8c5973..747ac9e 100644 (file)
@@ -18,34 +18,233 @@ PVOID CmBattPowerCallBackRegistration;
 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 == 1)
+        {
+            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 if (DeviceExtension->ArFlag & CMBATT_AR_NOTIFY)
+    {
+        /* The only known notification is AC/DC change. Loop device objects. */
+        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
@@ -74,7 +273,7 @@ CmBattUnload(IN PDRIVER_OBJECT DriverObject)
 
 NTSTATUS
 NTAPI
-CmBattVerifyStaticInfo(ULONG StaData,
+CmBattVerifyStaticInfo(PCMBATT_DEVICE_EXTENSION DeviceExtension,
                        ULONG BatteryTag)
 {
     UNIMPLEMENTED;
@@ -146,71 +345,896 @@ Complete:
 
 NTSTATUS
 NTAPI
-CmBattIoctl(PDEVICE_OBJECT DeviceObject,
-            PIRP Irp)
+CmBattIoctl(IN PDEVICE_OBJECT DeviceObject,
+            IN PIRP Irp)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PCMBATT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IoStackLocation;
+    ULONG IoControlCode, OutputBufferLength, InputBufferLength;
+    PAGED_CODE();
+    if (CmBattDebug & 2) DbgPrint("CmBattIoctl\n");
+
+    /* Acquire the remove lock */
+    Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, 0);
+    if (!NT_SUCCESS(Status))
+    {
+        /* It's too late, fail */
+        Irp->IoStatus.Status = STATUS_DEVICE_REMOVED;
+        IofCompleteRequest(Irp, IO_NO_INCREMENT);
+        return STATUS_DEVICE_REMOVED;
+    }
+    
+    /* There's nothing to do for an AC adapter */
+    if (DeviceExtension->FdoType == CmBattAcAdapter)
+    {
+        /* Pass it down, and release the remove lock */
+        IoSkipCurrentIrpStackLocation(Irp);
+        Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp);
+        IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
+        return Status;
+    }
+    
+    /* Send to class driver */
+    Status = BatteryClassIoctl(DeviceExtension->ClassData, Irp);
+    if (Status == STATUS_NOT_SUPPORTED)
+    {
+        /* Read IOCTL information from IRP stack */
+        IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+        IoControlCode = IoStackLocation->Parameters.DeviceIoControl.IoControlCode;
+        OutputBufferLength = IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength;
+        InputBufferLength = IoStackLocation->Parameters.DeviceIoControl.InputBufferLength;
+        if (CmBattDebug & 4)
+            DbgPrint("CmBattIoctl: Received  Direct Access IOCTL %x\n", IoControlCode);
+    
+        /* Handle internal IOCTLs */
+        switch (IoControlCode)
+        {
+            case IOCTL_BATTERY_QUERY_UNIQUE_ID:
+            
+                /* Data is 4 bytes long */
+                if (OutputBufferLength == sizeof(ULONG))
+                {
+                    /* Query it */
+                    Status = CmBattGetUniqueId(DeviceExtension->PdoDeviceObject,
+                                               Irp->AssociatedIrp.SystemBuffer);
+                    if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ULONG);
+                }
+                else
+                {
+                    /* Buffer size invalid */
+                    Status = STATUS_INVALID_BUFFER_SIZE;
+                }
+                break;
+            
+            case IOCTL_BATTERY_QUERY_STA:
+            
+                /* Data is 4 bytes long */
+                if (OutputBufferLength == sizeof(ULONG))
+                {
+                    /* Query it */
+                    Status = CmBattGetStaData(DeviceExtension->PdoDeviceObject,
+                                              Irp->AssociatedIrp.SystemBuffer);
+                    if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ULONG);
+                }
+                else
+                {
+                    /* Buffer size invalid */
+                    Status = STATUS_INVALID_BUFFER_SIZE;
+                }
+                break;
+            
+            case IOCTL_BATTERY_QUERY_PSR:
+            
+                /* Data is 4 bytes long */
+                if (OutputBufferLength == sizeof(ULONG))
+                {
+                    /* Do we have an AC adapter? */
+                    if (AcAdapterPdo)
+                    {
+                        /* Query it */
+                        Status = CmBattGetPsrData(AcAdapterPdo,
+                                                  Irp->AssociatedIrp.SystemBuffer);
+                        if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ULONG);
+                    }
+                    else
+                    {
+                        /* No adapter, just a battery, so fail */
+                        Status = STATUS_NO_SUCH_DEVICE;
+                    }
+                }
+                else
+                {
+                    /* Buffer size invalid */
+                    Status = STATUS_INVALID_BUFFER_SIZE;
+                }
+                break;
+                
+            case IOCTL_BATTERY_SET_TRIP_POINT:
+            
+                /* Data is 4 bytes long */
+                if (InputBufferLength == sizeof(ULONG))
+                {
+                    /* Query it */
+                    Status = CmBattSetTripPpoint(DeviceExtension,
+                                                 *(PULONG)Irp->AssociatedIrp.SystemBuffer);
+                    Irp->IoStatus.Information = 0;
+                }
+                else
+                {
+                    /* Buffer size invalid */
+                    Status = STATUS_INVALID_BUFFER_SIZE;
+                }
+                break;
+    
+            case IOCTL_BATTERY_QUERY_BIF:
+            
+                /* Data is 1060 bytes long */
+                if (OutputBufferLength == sizeof(ACPI_BIF_DATA))
+                {
+                    /* Query it */
+                    Status = CmBattGetBifData(DeviceExtension,
+                                              Irp->AssociatedIrp.SystemBuffer);
+                    if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ACPI_BIF_DATA);
+                }
+                else
+                {
+                    /* Buffer size invalid */
+                    Status = STATUS_INVALID_BUFFER_SIZE;
+                }
+                break;
+            
+            case IOCTL_BATTERY_QUERY_BST:
+            
+                /* Data is 16 bytes long */
+                if (OutputBufferLength == sizeof(ACPI_BST_DATA))
+                {
+                    /* Query it */
+                    Status = CmBattGetBstData(DeviceExtension,
+                                              Irp->AssociatedIrp.SystemBuffer);
+                    if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ACPI_BST_DATA);
+                }
+                else
+                {
+                    /* Buffer size invalid */
+                    Status = STATUS_INVALID_BUFFER_SIZE;
+                }
+                break;
+            
+            default:
+            
+                /* Unknown, let us pass it on to ACPI */
+                if (CmBattDebug & 0xC)
+                    DbgPrint("CmBattIoctl: Unknown IOCTL %x\n", IoControlCode);
+                break;
+        }
+        
+        /* Did someone pick it up? */
+        if (Status != STATUS_NOT_SUPPORTED)
+        {
+            /* Complete the request */
+            Irp->IoStatus.Status = Status;
+            IofCompleteRequest(Irp, IO_NO_INCREMENT);
+        }
+        else
+        {
+            /* Still unsupported, try ACPI */
+            IoSkipCurrentIrpStackLocation(Irp);
+            Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp);
+        }
+    }
+
+    /* Release the remove lock and return status */
+    IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
+    return Status;
 }
 
 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
 NTAPI
-CmBattQueryInformation(PCMBATT_DEVICE_EXTENSION DeviceExtension,
-                       ULONG BatteryTag,
-                       BATTERY_QUERY_INFORMATION_LEVEL Level,
-                       OPTIONAL LONG AtRate,
-                       PVOID Buffer,
-                       ULONG BufferLength,
-                       PULONG ReturnedLength)
+CmBattQueryInformation(IN PCMBATT_DEVICE_EXTENSION FdoExtension,
+                       IN ULONG Tag,
+                       IN BATTERY_QUERY_INFORMATION_LEVEL InfoLevel,
+                       IN OPTIONAL LONG AtRate,
+                       IN PVOID Buffer,
+                       IN ULONG BufferLength,
+                       OUT PULONG ReturnedLength)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED; 
+    NTSTATUS Status;
+    PVOID QueryData = NULL;
+    ULONG QueryLength = 0;
+    ULONG RemainingTime = 0;
+    ANSI_STRING TempString;
+    UNICODE_STRING TempString2;
+    WCHAR InfoBuffer[256];
+    WCHAR TempBuffer[256];
+    UNICODE_STRING InfoString;
+    ULONG RemainingCapacity;
+    BATTERY_REPORTING_SCALE BatteryReportingScale[2];
+    LONG Rate;
+    PAGED_CODE();
+    if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO))
+        DbgPrint("CmBattQueryInformation - Tag (%d) Device %d, Informationlevel %d\n",
+                 Tag,
+                 FdoExtension->DeviceId,
+                 InfoLevel);
+
+    /* Check ACPI Data */
+    Status = CmBattVerifyStaticInfo(FdoExtension, Tag);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Check what caller wants */
+    switch (InfoLevel)
+    {
+        case BatteryInformation:
+            /* Just return our static information */
+            QueryData = &FdoExtension->BatteryInformation;
+            QueryLength = sizeof(BATTERY_INFORMATION);
+            break;
+        
+        case BatteryGranularityInformation:
+        
+            /* Return our static information, we have two scales */
+            BatteryReportingScale[0].Granularity = FdoExtension->BatteryCapacityGranularity1;
+            BatteryReportingScale[0].Capacity = FdoExtension->BatteryInformation.DefaultAlert1;
+            BatteryReportingScale[1].Granularity = FdoExtension->BatteryCapacityGranularity2;
+            BatteryReportingScale[1].Capacity = FdoExtension->BatteryInformation.DesignedCapacity;
+            QueryData = BatteryReportingScale;
+            QueryLength = sizeof(BATTERY_REPORTING_SCALE) * 2;
+            break;
+            
+        case BatteryEstimatedTime:
+        
+            /* Check if it's been more than 2 1/2 minutes since the last change */
+            if ((KeQueryInterruptTime() - 150000000) > (FdoExtension->InterruptTime))
+            {
+                /* Get new battery status */
+                CmBattGetBatteryStatus(FdoExtension, FdoExtension->Tag);
+                
+                /* If the caller didn't specify a rate, use our static one */
+                Rate = AtRate;
+                if (!Rate) Rate = FdoExtension->Rate;
+                
+                /* If we don't have a valid negative rate, use unknown value */
+                if (Rate >= 0) Rate = BATTERY_UNKNOWN_RATE;
+                
+                /* Grab the remaining capacity */
+                RemainingCapacity = FdoExtension->RemainingCapacity;
+                
+                /* See if we don't know one or the other */
+                if ((Rate == BATTERY_UNKNOWN_RATE) ||
+                    (RemainingCapacity == BATTERY_UNKNOWN_CAPACITY))
+                {
+                    /* If the battery is discharging, we can't give out a time */
+                    if ((FdoExtension->BstData.State & ACPI_BATT_STAT_DISCHARG) &&
+                        (CmBattDebug & CMBATT_GENERIC_WARNING))
+                            DbgPrint("CmBattQueryInformation: Can't calculate EstimatedTime.\n");
+                    
+                    /* Check if we don't have a rate and capacity is going down */
+                    if ((FdoExtension->Rate == BATTERY_UNKNOWN_RATE) &&
+                        (FdoExtension->BstData.State & ACPI_BATT_STAT_DISCHARG))
+                    {
+                        /* We have to fail, since we lack data */
+                        Status = STATUS_INVALID_DEVICE_REQUEST;
+                        if (CmBattDebug & CMBATT_GENERIC_WARNING)
+                            DbgPrint("----------------------   PresentRate = BATTERY_UNKNOWN_RATE\n");
+                    }
+                    
+                    /* If we don't have capacity, the rate is useless */
+                    if (RemainingCapacity == BATTERY_UNKNOWN_CAPACITY)
+                    {
+                        /* We have to fail the request */
+                        Status = STATUS_INVALID_DEVICE_REQUEST;
+                        if (CmBattDebug & CMBATT_GENERIC_WARNING)
+                            DbgPrint("----------------------   RemainingCapacity = BATTERY_UNKNOWN_CAPACITY\n");
+                    }
+                }
+                else
+                {
+                    /* We have data, but is it valid? */
+                    if (RemainingCapacity > 0x123456)
+                    {
+                        /* The capacity seems bogus, so don't use it */
+                        if (CmBattDebug & CMBATT_ACPI_WARNING)
+                            DbgPrint("CmBattQueryInformation: Data Overflow in calculating Remaining Capacity.\n");
+                    }
+                    else
+                    {
+                        /* Compute the remaining time in seconds, based on rate */
+                        RemainingTime = (RemainingCapacity * 3600) / -Rate;
+                    }
+                }
+            }
+            
+            /* Return the remaining time */
+            QueryData = &RemainingTime;
+            QueryLength = sizeof(ULONG);
+            break;
+            
+        case BatteryDeviceName:
+        
+            /* Build the model number string */
+            RtlInitAnsiString(&TempString, FdoExtension->ModelNumber);
+
+            /* Convert it to Unicode */
+            InfoString.Buffer = InfoBuffer;
+            InfoString.MaximumLength = sizeof(InfoBuffer);            
+            Status = RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0);
+            
+            /* Return the unicode buffer */
+            QueryData = InfoString.Buffer;
+            QueryLength = InfoString.Length;
+            break;
+            
+        case BatteryTemperature:
+        case BatteryManufactureDate:
+        
+            /* We don't support these */
+            Status = STATUS_INVALID_DEVICE_REQUEST;
+            break;
+            
+        case BatteryManufactureName:
+            
+            /* Build the OEM info string */
+            RtlInitAnsiString(&TempString, FdoExtension->OemInfo);
+            
+            /* Convert it to Unicode */
+            InfoString.Buffer = InfoBuffer;
+            InfoString.MaximumLength = sizeof(InfoBuffer);
+            Status = RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0);
+            
+            /* Return the unicode buffer */
+            QueryData = InfoString.Buffer;
+            QueryLength = InfoString.Length;
+            break;
+            
+        case BatteryUniqueID:
+
+            /* Build the serial number string */
+            RtlInitAnsiString(&TempString, FdoExtension->SerialNumber);
+
+            /* Convert it to Unicode */
+            InfoString.Buffer = InfoBuffer;
+            InfoString.MaximumLength = sizeof(InfoBuffer);
+            RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0);
+
+            /* Setup a temporary string for concatenation */
+            TempString2.Buffer = TempBuffer;
+            TempString2.MaximumLength = sizeof(TempBuffer);
+            
+            /* Check if there's an OEM string */
+            if (FdoExtension->OemInfo[0])
+            {
+                /* Build the OEM info string */
+                RtlInitAnsiString(&TempString, FdoExtension->OemInfo);
+              
+                /* Convert it to Unicode and append it */
+                RtlAnsiStringToUnicodeString(&TempString2, &TempString, 0);
+                RtlAppendUnicodeStringToString(&InfoString, &TempString2);
+            }
+            
+            /* Build the model number string */
+            RtlInitAnsiString(&TempString, FdoExtension->ModelNumber);
+            
+            /* Convert it to Unicode and append it */
+            RtlAnsiStringToUnicodeString(&TempString2, &TempString, 0);
+            RtlAppendUnicodeStringToString(&InfoString, &TempString2);
+            
+            /* Return the final appended string */
+            QueryData = InfoString.Buffer;
+            QueryLength = InfoString.Length;
+            break;
+            
+        default:
+        
+            /* Everything else is unknown */
+            Status = STATUS_INVALID_PARAMETER;
+            break;
+    }
+
+    /* Return the required length and check if the caller supplied enough */
+    *ReturnedLength = QueryLength;
+    if (BufferLength < QueryLength) Status = STATUS_BUFFER_TOO_SMALL;
+
+    /* Copy the data if there's enough space and it exists */
+    if ((NT_SUCCESS(Status)) && (QueryData)) RtlCopyMemory(Buffer, QueryData, QueryLength);
+      
+    /* Return function result */
+    return Status;
 }
 
 NTSTATUS
 NTAPI
-CmBattQueryStatus(PCMBATT_DEVICE_EXTENSION DeviceExtension,
-                  ULONG BatteryTag,
-                  PBATTERY_STATUS BatteryStatus)
+CmBattQueryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension,
+                  IN ULONG Tag,
+                  IN PBATTERY_STATUS BatteryStatus)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+    PAGED_CODE();
+    if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO))
+        DbgPrint("CmBattQueryStatus - Tag (%d) Device %x\n", Tag, DeviceExtension->DeviceId);
+    
+    /* Query ACPI information */
+    Status = CmBattGetBatteryStatus(DeviceExtension, Tag);
+    if (NT_SUCCESS(Status))
+    {
+        BatteryStatus->PowerState = DeviceExtension->State;
+        BatteryStatus->Capacity = DeviceExtension->RemainingCapacity;
+        BatteryStatus->Voltage = DeviceExtension->PresentVoltage;
+        BatteryStatus->Rate = DeviceExtension->Rate;
+    }
+    
+    /* Return status */
+    if (CmBattDebug & (CMBATT_GENERIC_INFO))
+        DbgPrint("CmBattQueryStatus: Returning [%#08lx][%#08lx][%#08lx][%#08lx]\n",
+                 BatteryStatus->PowerState,
+                 BatteryStatus->Capacity,
+                 BatteryStatus->Voltage,
+                 BatteryStatus->Rate);
+    return Status;
 }
 
 NTSTATUS
@@ -233,28 +1257,24 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
     {
         /* Fail if we're out of memory this early */
         if (CmBattDebug & CMBATT_GENERIC_WARNING)
-        {
             DbgPrint("CmBatt: Couldn't allocate pool for registry path.");
-        }
         return STATUS_INSUFFICIENT_RESOURCES;
     }
     
     /* Buffer allocated, copy the string */
     RtlCopyUnicodeString(&GlobalRegistryPath, RegistryPath);
     if (CmBattDebug & CMBATT_GENERIC_INFO)
-    {
         DbgPrint("CmBatt DriverEntry - Obj (%08x) Path \"%ws\"\n",
                  DriverObject,
                  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;
@@ -276,9 +1296,7 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
         /* No callback, fail */
         CmBattPowerCallBackObject = 0;
         if (CmBattDebug & CMBATT_GENERIC_WARNING)
-        {
             DbgPrint("CmBattRegisterPowerCallBack: failed status=0x%08x\n", Status);
-        }
     }
     else
     {
@@ -296,9 +1314,7 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
         {
             ObfDereferenceObject(CmBattPowerCallBackObject);
             if (CmBattDebug & CMBATT_GENERIC_WARNING)
-            {
                 DbgPrint("CmBattRegisterPowerCallBack: ExRegisterCallback failed.\n");
-            }
         }
         
         /* All good */