[CMBATT]: Implement PnP handling. Only the ACPI-facing interface needs to be written...
[reactos.git] / reactos / drivers / bus / acpi / cmbatt / cmbatt.c
index 45903cb..747ac9e 100644 (file)
@@ -19,34 +19,232 @@ 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
@@ -147,38 +345,434 @@ 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
@@ -675,12 +1269,12 @@ DriverEntry(IN PDRIVER_OBJECT 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;