570 lines
13 KiB
C
570 lines
13 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ApmBatt.c
|
||
|
||
Abstract:
|
||
|
||
Control Method Battery Miniport Driver - Wacked to work on APM.
|
||
|
||
Author:
|
||
|
||
Bryan Willman
|
||
Ron Mosgrove (Intel)
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "ApmBattp.h"
|
||
#include "ntddk.h"
|
||
#include "ntapm.h"
|
||
|
||
|
||
ULONG ApmBattDebug = APMBATT_ERROR;
|
||
//ULONG ApmBattDebug = -1;
|
||
|
||
//
|
||
// Prototypes
|
||
//
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
);
|
||
|
||
NTSTATUS
|
||
ApmBattOpenClose(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
ApmBattIoctl(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
|
||
//
|
||
// Globals. Globals are a little odd in a device driver,
|
||
// but this is an odd driver
|
||
//
|
||
|
||
//
|
||
// Vector used to call NtApm.sys (our PDO) and ask about
|
||
// current battery status
|
||
//
|
||
ULONG (*NtApmGetBatteryLevel)() = NULL;
|
||
|
||
//
|
||
// APM event notifications and SET_POWER ops will cause
|
||
// this value to be incremented.
|
||
//
|
||
ULONG TagValue = 1;
|
||
|
||
//
|
||
// If somebody tries to claim there is more than 1 APM driver battery
|
||
// in the system, somebody somewhere is very confused. So keep track
|
||
// and forbig this.
|
||
//
|
||
ULONG DeviceCount = 0;
|
||
|
||
//
|
||
//
|
||
//
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(INIT,DriverEntry)
|
||
#pragma alloc_text(PAGE,ApmBattQueryTag)
|
||
#pragma alloc_text(PAGE,ApmBattQueryInformation)
|
||
#pragma alloc_text(PAGE,ApmBattQueryStatus)
|
||
#pragma alloc_text(PAGE,ApmBattSetStatusNotify)
|
||
#pragma alloc_text(PAGE,ApmBattDisableStatusNotify)
|
||
#pragma alloc_text(PAGE,ApmBattOpenClose)
|
||
#pragma alloc_text(PAGE,ApmBattIoctl)
|
||
#endif
|
||
|
||
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the ACPI Embedded Controller Driver
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to driver object created by system.
|
||
|
||
RegistryPath - Pointer to the Unicode name of the registry path
|
||
for this driver.
|
||
|
||
Return Value:
|
||
|
||
The function value is the final status from the initialization operation.
|
||
|
||
--*/
|
||
{
|
||
ApmBattPrint (APMBATT_TRACE, ("ApmBatt DriverEntry - Obj (%08x) Path (%08x)\n",
|
||
DriverObject, RegistryPath));
|
||
//
|
||
// Set up the device driver entry points.
|
||
//
|
||
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ApmBattIoctl;
|
||
DriverObject->MajorFunction[IRP_MJ_CREATE] = ApmBattOpenClose;
|
||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = ApmBattOpenClose;
|
||
|
||
DriverObject->MajorFunction[IRP_MJ_POWER] = ApmBattPowerDispatch;
|
||
DriverObject->MajorFunction[IRP_MJ_PNP] = ApmBattPnpDispatch;
|
||
DriverObject->DriverExtension->AddDevice = ApmBattAddDevice;
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
ApmBattOpenClose(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the routine called as a result of a Open or Close on the device
|
||
|
||
Arguments:
|
||
|
||
|
||
DeviceObject - Battery for request
|
||
Irp - IO request
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - no way to fail this puppy
|
||
|
||
--*/
|
||
{
|
||
PAGED_CODE();
|
||
|
||
ApmBattPrint (APMBATT_TRACE, ("ApmBattOpenClose\n"));
|
||
|
||
//
|
||
// Complete the request and return status.
|
||
//
|
||
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
Irp->IoStatus.Information = 0;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
ApmBattIoctl(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
IOCTL handler. As this is an exclusive battery device, send the
|
||
Irp to the battery class driver to handle battery IOCTLs.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Battery for request
|
||
Irp - IO request
|
||
|
||
Return Value:
|
||
|
||
Status of request
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
PCM_BATT ApmBatt;
|
||
|
||
|
||
PAGED_CODE();
|
||
|
||
ApmBattPrint (APMBATT_TRACE, ("ApmBattIoctl\n"));
|
||
|
||
ApmBatt = (PCM_BATT) DeviceObject->DeviceExtension;
|
||
Status = BatteryClassIoctl (ApmBatt->Class, Irp);
|
||
|
||
if (Status == STATUS_NOT_SUPPORTED) {
|
||
//
|
||
// Not for the battery, complete it
|
||
//
|
||
|
||
Irp->IoStatus.Status = Status;
|
||
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
ApmBattQueryTag (
|
||
IN PVOID Context,
|
||
OUT PULONG TagPtr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
BATTERY CLASS ENTRY
|
||
|
||
Called by the class driver to retrieve the batteries current tag value
|
||
|
||
The battery class driver will serialize all requests it issues to
|
||
the miniport for a given battery.
|
||
|
||
Arguments:
|
||
|
||
Context - Miniport context value for battery
|
||
TagPtr - Pointer to return current tag
|
||
|
||
Return Value:
|
||
|
||
Success if there is a battery currently installed, else no such device.
|
||
|
||
--*/
|
||
{
|
||
ULONG BatteryLevel;
|
||
UNREFERENCED_PARAMETER(Context);
|
||
PAGED_CODE();
|
||
ApmBattPrint ((APMBATT_TRACE | APMBATT_MINI),
|
||
("ApmBattQueryTag - TagValue = %08x\n", TagValue));
|
||
//
|
||
// The code that catches APM event notification, and the code
|
||
// that handles Power IRPs, will both increment the tag.
|
||
// We simply report that.
|
||
//
|
||
|
||
*TagPtr = TagValue;
|
||
|
||
//
|
||
// Call ntapm, it will return a DWORD with the relevent data in it,
|
||
// crack this DWORD, and fill this stuff in.
|
||
//
|
||
if (NtApmGetBatteryLevel) {
|
||
BatteryLevel = NtApmGetBatteryLevel();
|
||
if ((BatteryLevel & NTAPM_NO_BATT) || (BatteryLevel & NTAPM_NO_SYS_BATT)) {
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
} else {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
} else {
|
||
//
|
||
// if we cannot get battery status, it's likely we don't have
|
||
// a battery, so say we don't have one.
|
||
//
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
ApmBattQueryInformation (
|
||
IN PVOID Context,
|
||
IN ULONG BatteryTag,
|
||
IN BATTERY_QUERY_INFORMATION_LEVEL Level,
|
||
IN ULONG AtRate OPTIONAL,
|
||
OUT PVOID Buffer,
|
||
IN ULONG BufferLength,
|
||
OUT PULONG ReturnedLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
BATTERY CLASS ENTRY
|
||
|
||
Called by the class driver to retrieve battery information
|
||
|
||
The battery class driver will serialize all requests it issues to
|
||
the miniport for a given battery.
|
||
|
||
We return invalid parameter when we can't handle a request for a
|
||
specific level of information. This is defined in the battery class spec.
|
||
|
||
Arguments:
|
||
|
||
Context - Miniport context value for battery
|
||
BatteryTag - Tag of current battery
|
||
Level - type of information required
|
||
AtRate - Used only when Level==BatteryEstimatedTime
|
||
Buffer - Location for the information
|
||
BufferLength - Length in bytes of the buffer
|
||
ReturnedLength - Length in bytes of the returned data
|
||
|
||
Return Value:
|
||
|
||
Success if there is a battery currently installed, else no such device.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
PVOID ReturnBuffer;
|
||
ULONG ReturnBufferLength;
|
||
ULONG CapabilityVector = (BATTERY_SYSTEM_BATTERY | BATTERY_CAPACITY_RELATIVE);
|
||
BATTERY_INFORMATION bi;
|
||
|
||
|
||
PAGED_CODE();
|
||
|
||
ApmBattPrint ((APMBATT_TRACE | APMBATT_MINI),
|
||
("ApmBattQueryInformation Level=%08xl\n", Level));
|
||
|
||
//
|
||
// We cannot tell (reliably/safely) if there is a battery
|
||
// present or not, so always return what the query code tells us
|
||
//
|
||
|
||
ReturnBuffer = NULL;
|
||
ReturnBufferLength = 0;
|
||
Status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// Get the info requested
|
||
//
|
||
|
||
switch (Level) {
|
||
case BatteryInformation:
|
||
ApmBattPrint((APMBATT_TRACE|APMBATT_MINI), ("Batteryinformation\n"));
|
||
RtlZeroMemory(&bi, sizeof(bi));
|
||
bi.Capabilities = CapabilityVector;
|
||
bi.Technology = BATTERY_SECONDARY_CHARGABLE;
|
||
bi.DesignedCapacity = 100;
|
||
bi.FullChargedCapacity = UNKNOWN_CAPACITY;
|
||
ReturnBuffer = (PVOID) &bi;
|
||
ReturnBufferLength = sizeof(bi);
|
||
break;
|
||
|
||
case BatteryEstimatedTime:
|
||
case BatteryTemperature:
|
||
case BatteryGranularityInformation:
|
||
case BatteryDeviceName:
|
||
case BatteryManufactureDate:
|
||
case BatteryManufactureName:
|
||
case BatteryUniqueID:
|
||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||
break;
|
||
|
||
default:
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Done, return buffer if needed
|
||
//
|
||
*ReturnedLength = ReturnBufferLength;
|
||
if (BufferLength < ReturnBufferLength) {
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
}
|
||
|
||
if (NT_SUCCESS(Status) && ReturnBuffer) {
|
||
RtlZeroMemory (Buffer, BufferLength); // Clear entire user buffer
|
||
RtlCopyMemory (Buffer, ReturnBuffer, ReturnBufferLength); // Copy what's needed
|
||
}
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
ApmBattQueryStatus (
|
||
IN PVOID Context,
|
||
IN ULONG BatteryTag,
|
||
OUT PBATTERY_STATUS BatteryStatus
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
BATTERY CLASS ENTRY
|
||
|
||
Called by the class driver to retrieve the batteries current status
|
||
|
||
The battery class driver will serialize all requests it issues to
|
||
the miniport for a given battery.
|
||
|
||
Arguments:
|
||
|
||
Context - Miniport context value for battery
|
||
BatteryTag - Tag of current battery
|
||
BatteryStatus - Pointer to structure to return the current battery status
|
||
|
||
Return Value:
|
||
|
||
Success if there is a battery currently installed, else no such device.
|
||
|
||
--*/
|
||
{
|
||
ULONG BatteryLevel;
|
||
|
||
PAGED_CODE();
|
||
|
||
ApmBattPrint ((APMBATT_TRACE | APMBATT_MINI), ("ApmBattQueryStatus\n"));
|
||
|
||
//
|
||
// Call ntapm, it will return a DWORD with the relevent data in it,
|
||
// crack this DWORD, and fill this stuff in.
|
||
//
|
||
if (NtApmGetBatteryLevel) {
|
||
BatteryLevel = NtApmGetBatteryLevel();
|
||
BatteryStatus->PowerState = ((BatteryLevel & NTAPM_BATTERY_STATE) >> NTAPM_BATTERY_STATE_SHIFT);
|
||
BatteryStatus->Capacity = BatteryLevel & NTAPM_POWER_PERCENT;
|
||
BatteryStatus->Voltage = UNKNOWN_VOLTAGE;
|
||
BatteryStatus->Current = UNKNOWN_RATE;
|
||
|
||
ApmBattPrint((APMBATT_MINI), ("ApmBattQueryStatus: BatteryLevel = %08lx\n", BatteryLevel));
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
} else {
|
||
ApmBattPrint((APMBATT_ERROR), ("ApmBattQueryStatus: failure NtApmGetBatteryLevel == NULL\n"));
|
||
//
|
||
// return some "safe" values to keep from looping forever
|
||
//
|
||
BatteryStatus->PowerState = 0;
|
||
BatteryStatus->Capacity = 1;
|
||
BatteryStatus->Voltage = UNKNOWN_VOLTAGE;
|
||
BatteryStatus->Current = UNKNOWN_RATE;
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
ApmBattSetStatusNotify (
|
||
IN PVOID Context,
|
||
IN ULONG BatteryTag,
|
||
IN PBATTERY_NOTIFY Notify
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
BATTERY CLASS ENTRY
|
||
|
||
Called by the class driver to set the batteries current notification
|
||
setting. When the battery trips the notification, one call to
|
||
BatteryClassStatusNotify is issued. If an error is returned, the
|
||
class driver will poll the battery status - primarily for capacity
|
||
changes. Which is to say the miniport should still issue BatteryClass-
|
||
StatusNotify whenever the power state changes.
|
||
|
||
The class driver will always set the notification level it needs
|
||
after each call to BatteryClassStatusNotify.
|
||
|
||
The battery class driver will serialize all requests it issues to
|
||
the miniport for a given battery.
|
||
|
||
Arguments:
|
||
|
||
Context - Miniport context value for battery
|
||
BatteryTag - Tag of current battery
|
||
BatteryNotify - The notification setting
|
||
|
||
Return Value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// need to fill this in
|
||
//
|
||
ApmBattPrint (APMBATT_TRACE, ("ApmBattSetStatusNotify\n"));
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
ApmBattDisableStatusNotify (
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
BATTERY CLASS ENTRY
|
||
|
||
Called by the class driver to disable the notification setting
|
||
for the battery supplied by Context. Note, to disable a setting
|
||
does not require the battery tag. Any notification is to be
|
||
masked off until a subsequent call to ApmBattSetStatusNotify.
|
||
|
||
The battery class driver will serialize all requests it issues to
|
||
the miniport for a given battery.
|
||
|
||
Arguments:
|
||
|
||
Context - Miniport context value for battery
|
||
|
||
Return Value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// need to fill this in
|
||
//
|
||
ApmBattPrint (APMBATT_TRACE, ("ApmBattDisableStatusNotify\n"));
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
VOID
|
||
ApmBattPowerNotifyHandler (
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
NTAPM CALLBACK
|
||
|
||
This routine fields power device notifications from the APM driver.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
ApmBattPrint (APMBATT_TRACE, ("ApmBattPowerNotifyHandler\n"));
|
||
// DbgBreakPoint();
|
||
TagValue++;
|
||
BatteryClassStatusNotify(ApmGlobalClass);
|
||
}
|
||
|