windows-nt/Source/XPSP1/NT/drivers/apm/apmbatt/i386/apmbatt.c

570 lines
13 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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);
}