1000 lines
24 KiB
C
1000 lines
24 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
CmBatt.c
|
||
|
||
Abstract:
|
||
|
||
Control Method Battery Miniport Driver
|
||
|
||
Author:
|
||
|
||
Ron Mosgrove (Intel)
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "CmBattp.h"
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, CmBattSendDownStreamIrp)
|
||
#pragma alloc_text(PAGE, CmBattGetUniqueId)
|
||
#pragma alloc_text(PAGE, CmBattGetStaData)
|
||
#pragma alloc_text(PAGE, CmBattSetTripPpoint)
|
||
#endif
|
||
|
||
#define EXPECTED_DATA_SIZE 512
|
||
|
||
NTSTATUS
|
||
CmBattSendDownStreamIrp(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN ULONG Ioctl,
|
||
IN PVOID InputBuffer,
|
||
IN ULONG InputSize,
|
||
IN PVOID OutputBuffer,
|
||
IN ULONG OutputSize
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Called to send a request to the Pdo
|
||
|
||
Arguments:
|
||
|
||
Pdo - The request is sent to this device object
|
||
Ioctl - the request
|
||
InputBuffer - The incoming request
|
||
InputSize - The size of the incoming request
|
||
OutputBuffer - The answer
|
||
OutputSize - The size of the answer buffer
|
||
|
||
Return Value:
|
||
|
||
NT Status of the operation
|
||
|
||
--*/
|
||
{
|
||
IO_STATUS_BLOCK ioBlock;
|
||
KEVENT event;
|
||
NTSTATUS status;
|
||
PIRP irp;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Initialize an event to wait on
|
||
//
|
||
KeInitializeEvent( &event, SynchronizationEvent, FALSE );
|
||
|
||
//
|
||
// Build the request
|
||
//
|
||
irp = IoBuildDeviceIoControlRequest(
|
||
Ioctl,
|
||
Pdo,
|
||
InputBuffer,
|
||
InputSize,
|
||
OutputBuffer,
|
||
OutputSize,
|
||
FALSE,
|
||
&event,
|
||
&ioBlock
|
||
);
|
||
if (!irp) {
|
||
|
||
CmBattPrint((CMBATT_ERROR | CMBATT_CM_EXE),
|
||
("CmBattSendDownStreamIrp: Failed to allocate Irp\n"));
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
CmBattPrint(
|
||
CMBATT_CM_EXE,
|
||
("CmBattSendDownStreamIrp: Irp %x [Tid] %x\n", irp, GetTid() )
|
||
);
|
||
|
||
//
|
||
// Pass request to Pdo, always wait for completion routine
|
||
//
|
||
status = IoCallDriver(Pdo, irp);
|
||
if (status == STATUS_PENDING) {
|
||
|
||
//
|
||
// Wait for the irp to be completed, then grab the real status code
|
||
//
|
||
KeWaitForSingleObject(
|
||
&event,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
status = ioBlock.Status;
|
||
|
||
}
|
||
|
||
//
|
||
// Sanity check the data
|
||
//
|
||
if (OutputBuffer != NULL) {
|
||
|
||
if ( ( (PACPI_EVAL_OUTPUT_BUFFER) OutputBuffer)->Signature != ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE ||
|
||
( (PACPI_EVAL_OUTPUT_BUFFER) OutputBuffer)->Count == 0) {
|
||
|
||
status = STATUS_ACPI_INVALID_DATA;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
CmBattPrint(
|
||
CMBATT_CM_EXE,
|
||
("CmBattSendDownStreamIrp: Irp %x completed %x! [Tid] %x\n",
|
||
irp, status, GetTid() )
|
||
);
|
||
|
||
//
|
||
// Done
|
||
//
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
CmBattGetUniqueId(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
OUT PULONG UniqueId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Obtain the UID (unique ID) for a battery.
|
||
|
||
Arguments:
|
||
|
||
CmBatt - The extension for this device.
|
||
UniqueId - Pointer to where the ID is stored.
|
||
|
||
Return Value:
|
||
|
||
NT Status of the operation
|
||
|
||
--*/
|
||
{
|
||
ACPI_EVAL_INPUT_BUFFER inputBuffer;
|
||
ACPI_EVAL_OUTPUT_BUFFER outputBuffer;
|
||
NTSTATUS status;
|
||
PACPI_METHOD_ARGUMENT argument;
|
||
|
||
PAGED_CODE();
|
||
|
||
CmBattPrint(
|
||
CMBATT_CM_EXE,
|
||
("CmBattGetUniqueId: Entered with Pdo %x Tid %x\n", Pdo, GetTid() )
|
||
);
|
||
|
||
ASSERT( UniqueId != NULL );
|
||
*UniqueId = 0;
|
||
|
||
//
|
||
// Fill in the input data
|
||
//
|
||
inputBuffer.MethodNameAsUlong = CM_UID_METHOD;
|
||
inputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
|
||
|
||
//
|
||
// Send the request along
|
||
//
|
||
status = CmBattSendDownStreamIrp(
|
||
Pdo,
|
||
IOCTL_ACPI_EVAL_METHOD,
|
||
&inputBuffer,
|
||
sizeof(ACPI_EVAL_INPUT_BUFFER),
|
||
&outputBuffer,
|
||
sizeof(ACPI_EVAL_OUTPUT_BUFFER)
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
CmBattPrint(
|
||
(CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetUniqueId: Failed _UID method - Status (0x%x)\n", status)
|
||
);
|
||
return status;
|
||
|
||
}
|
||
|
||
//
|
||
// Grab the argument
|
||
//
|
||
argument = outputBuffer.Argument;
|
||
status = GetDwordElement( argument, UniqueId );
|
||
CmBattPrint(
|
||
(CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetUniqueId: _UID method returned 0x%x\n", *UniqueId)
|
||
);
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
CmBattGetStaData(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
OUT PULONG ReturnStatus
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Called to get a device status via the _STA method. Generic, works for
|
||
any device with the _STA method (assuming caller has a Pdo).
|
||
|
||
Arguments:
|
||
|
||
Pdo - For the device.
|
||
ReturnStatus - Pointer to where the status data is placed.
|
||
|
||
Return Value:
|
||
|
||
NT Status of the operation
|
||
|
||
--*/
|
||
{
|
||
ACPI_EVAL_INPUT_BUFFER inputBuffer;
|
||
ACPI_EVAL_OUTPUT_BUFFER outputBuffer;
|
||
NTSTATUS status;
|
||
PACPI_METHOD_ARGUMENT argument;
|
||
|
||
PAGED_CODE();
|
||
|
||
CmBattPrint(
|
||
CMBATT_CM_EXE,
|
||
("CmBattGetStaData: Entered with Pdo %x Tid %x\n", Pdo, GetTid() )
|
||
);
|
||
|
||
ASSERT( ReturnStatus != NULL );
|
||
*ReturnStatus = 0x0;
|
||
|
||
//
|
||
// Fill in the input data
|
||
//
|
||
inputBuffer.MethodNameAsUlong = CM_STA_METHOD;
|
||
inputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
|
||
|
||
//
|
||
// Send the request along
|
||
//
|
||
status = CmBattSendDownStreamIrp(
|
||
Pdo,
|
||
IOCTL_ACPI_EVAL_METHOD,
|
||
&inputBuffer,
|
||
sizeof(ACPI_EVAL_INPUT_BUFFER),
|
||
&outputBuffer,
|
||
sizeof(ACPI_EVAL_OUTPUT_BUFFER)
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetStaData: Failed _STA method - Status (0x%x)\n", status)
|
||
);
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
|
||
}
|
||
|
||
//
|
||
// Grab the argument
|
||
//
|
||
argument = outputBuffer.Argument;
|
||
status = GetDwordElement( argument, ReturnStatus );
|
||
CmBattPrint(
|
||
(CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetStaData: _STA method returned %x \n", *ReturnStatus )
|
||
);
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
CmBattGetPsrData(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
OUT PULONG ReturnStatus
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Called to get the AC adapter device status via the _PSR method.
|
||
|
||
|
||
Arguments:
|
||
|
||
Pdo - For the device.
|
||
ReturnStatus - Pointer to where the status data is placed.
|
||
|
||
Return Value:
|
||
|
||
NT Status of the operation
|
||
|
||
--*/
|
||
{
|
||
ACPI_EVAL_INPUT_BUFFER inputBuffer;
|
||
ACPI_EVAL_OUTPUT_BUFFER outputBuffer;
|
||
NTSTATUS status;
|
||
PACPI_METHOD_ARGUMENT argument;
|
||
|
||
PAGED_CODE();
|
||
|
||
CmBattPrint(
|
||
CMBATT_CM_EXE,
|
||
("CmBattGetPsrData: Entered with Pdo %x Tid %x\n", Pdo, GetTid() )
|
||
);
|
||
|
||
ASSERT( ReturnStatus != NULL );
|
||
*ReturnStatus = 0x0;
|
||
|
||
//
|
||
// Fill in the input data
|
||
//
|
||
inputBuffer.MethodNameAsUlong = CM_PSR_METHOD;
|
||
inputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
|
||
|
||
//
|
||
// Send the request along
|
||
//
|
||
status = CmBattSendDownStreamIrp(
|
||
Pdo,
|
||
IOCTL_ACPI_EVAL_METHOD,
|
||
&inputBuffer,
|
||
sizeof(ACPI_EVAL_INPUT_BUFFER),
|
||
&outputBuffer,
|
||
sizeof(ACPI_EVAL_OUTPUT_BUFFER)
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetPsrData: Failed _PSR method - Status (0x%x)\n", status)
|
||
);
|
||
return status;
|
||
|
||
}
|
||
|
||
//
|
||
// Get the value
|
||
//
|
||
argument = outputBuffer.Argument;
|
||
status = GetDwordElement( argument, ReturnStatus );
|
||
CmBattPrint(
|
||
(CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetPsrData: _PSR method returned %x \n", *ReturnStatus )
|
||
);
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
CmBattSetTripPpoint(
|
||
IN PCM_BATT CmBatt,
|
||
IN ULONG TripPoint
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Called to set the tripPoint via the BTP control method.
|
||
|
||
Arguments:
|
||
|
||
CmBatt - The extension for this device.
|
||
TripPoint - The desired alarm value
|
||
|
||
Return Value:
|
||
|
||
NT Status of the operation
|
||
|
||
--*/
|
||
{
|
||
ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER inputBuffer;
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
CmBattPrint(
|
||
(CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattSetTripPpoint: _BTP Alarm Value %x Device %x Tid %x\n",
|
||
TripPoint, CmBatt->DeviceNumber, GetTid() )
|
||
);
|
||
|
||
//
|
||
// Fill in the input data
|
||
//
|
||
inputBuffer.MethodNameAsUlong = CM_BTP_METHOD;
|
||
inputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER_SIGNATURE;
|
||
inputBuffer.IntegerArgument = TripPoint;
|
||
|
||
//
|
||
// Send the request along
|
||
//
|
||
status = CmBattSendDownStreamIrp(
|
||
CmBatt->LowerDeviceObject,
|
||
IOCTL_ACPI_EVAL_METHOD,
|
||
&inputBuffer,
|
||
sizeof(ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER),
|
||
NULL,
|
||
0
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
CmBattPrint(
|
||
(CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattSetTripPpoint: Failed _BTP method on device %x - Status (0x%x)\n",
|
||
CmBatt->DeviceNumber, status)
|
||
);
|
||
|
||
}
|
||
|
||
//
|
||
// Done
|
||
//
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
CmBattGetBifData(
|
||
IN PCM_BATT CmBatt,
|
||
OUT PCM_BIF_BAT_INFO BifBuf
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Called to read the BIF package from ACPI
|
||
|
||
Arguments:
|
||
|
||
CmBatt - The extension for this device.
|
||
BifBuf - Output buffer for the BIF data
|
||
|
||
Return Value:
|
||
|
||
NT Status of the operation
|
||
|
||
--*/
|
||
{
|
||
ACPI_EVAL_INPUT_BUFFER inputBuffer;
|
||
NTSTATUS status;
|
||
PACPI_EVAL_OUTPUT_BUFFER outputBuffer;
|
||
PACPI_METHOD_ARGUMENT argument;
|
||
|
||
CmBattPrint(
|
||
CMBATT_CM_EXE,
|
||
("CmBattGetBifData: Buffer (0x%x) Device %x Tid %x\n",
|
||
BifBuf, CmBatt->DeviceNumber, GetTid() )
|
||
);
|
||
|
||
//
|
||
// Allocate a buffer for this
|
||
//
|
||
outputBuffer = ExAllocatePoolWithTag(
|
||
PagedPool,
|
||
EXPECTED_DATA_SIZE,
|
||
'MtaB'
|
||
);
|
||
if (!outputBuffer) {
|
||
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE),
|
||
("CmBattGetBifData: Failed to allocate Buffer\n")
|
||
);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
//
|
||
// Clear the buffers
|
||
//
|
||
RtlZeroMemory(outputBuffer, EXPECTED_DATA_SIZE);
|
||
RtlZeroMemory(BifBuf, sizeof(CM_BIF_BAT_INFO));
|
||
|
||
//
|
||
// Set the request data
|
||
//
|
||
inputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
|
||
inputBuffer.MethodNameAsUlong = CM_BIF_METHOD;
|
||
|
||
//
|
||
// Send the request along
|
||
//
|
||
status = CmBattSendDownStreamIrp(
|
||
CmBatt->LowerDeviceObject,
|
||
IOCTL_ACPI_EVAL_METHOD,
|
||
&inputBuffer,
|
||
sizeof(ACPI_EVAL_INPUT_BUFFER),
|
||
outputBuffer,
|
||
EXPECTED_DATA_SIZE
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBifData: Failed _BIF method on device %x - Status (0x%x)\n",
|
||
CmBatt->DeviceNumber, status)
|
||
);
|
||
goto CmBattGetBifDataExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Sanity check the return count
|
||
//
|
||
if (outputBuffer->Count != NUMBER_OF_BIF_ELEMENTS) {
|
||
|
||
//
|
||
// Package did not contain the correct number of elements to be a BIF
|
||
//
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBifData: _BIF returned %d elements. BIF requires %d\n",
|
||
outputBuffer->Count,
|
||
NUMBER_OF_BIF_ELEMENTS)
|
||
);
|
||
status = STATUS_ACPI_INVALID_DATA;
|
||
goto CmBattGetBifDataExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Look at the return arguments
|
||
//
|
||
argument = outputBuffer->Argument;
|
||
|
||
//
|
||
// Parse the package data that is returned. This should look like:
|
||
//
|
||
status = GetDwordElement (argument, &BifBuf->PowerUnit);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBifData: Failed to get PowerUnit\n")
|
||
);
|
||
goto CmBattGetBifDataExit;
|
||
}
|
||
|
||
argument = ACPI_METHOD_NEXT_ARGUMENT( argument );
|
||
status = GetDwordElement (argument, &BifBuf->DesignCapacity);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBifData: Failed to get DesignCapacity\n")
|
||
);
|
||
goto CmBattGetBifDataExit;
|
||
}
|
||
|
||
argument = ACPI_METHOD_NEXT_ARGUMENT( argument );
|
||
status = GetDwordElement (argument, &BifBuf->LastFullChargeCapacity);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBifData: Failed to get LastFullChargeCapacity\n")
|
||
);
|
||
goto CmBattGetBifDataExit;
|
||
}
|
||
|
||
argument = ACPI_METHOD_NEXT_ARGUMENT( argument );
|
||
status = GetDwordElement (argument, &BifBuf->BatteryTechnology);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBifData: Failed to get BatteryTechnology\n")
|
||
);
|
||
goto CmBattGetBifDataExit;
|
||
}
|
||
|
||
argument = ACPI_METHOD_NEXT_ARGUMENT( argument );
|
||
status = GetDwordElement (argument, &BifBuf->DesignVoltage);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBifData: Failed to get DesignVoltage\n")
|
||
);
|
||
goto CmBattGetBifDataExit;
|
||
}
|
||
|
||
argument = ACPI_METHOD_NEXT_ARGUMENT( argument );
|
||
status = GetDwordElement (argument, &BifBuf->DesignCapacityOfWarning);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBifData: Failed to get DesignCapacityOfWarning\n")
|
||
);
|
||
goto CmBattGetBifDataExit;
|
||
}
|
||
|
||
argument = ACPI_METHOD_NEXT_ARGUMENT( argument );
|
||
status = GetDwordElement (argument, &BifBuf->DesignCapacityOfLow);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBifData: Failed to get DesignCapacityOfLow\n")
|
||
);
|
||
goto CmBattGetBifDataExit;
|
||
}
|
||
|
||
argument = ACPI_METHOD_NEXT_ARGUMENT( argument );
|
||
status = GetDwordElement (argument, &BifBuf->BatteryCapacityGran_1);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBifData: Failed to get BatteryCapacityGran_1\n")
|
||
);
|
||
goto CmBattGetBifDataExit;
|
||
}
|
||
|
||
argument = ACPI_METHOD_NEXT_ARGUMENT( argument );
|
||
status = GetDwordElement (argument, &BifBuf->BatteryCapacityGran_2);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBifData: Failed to get BatteryCapacityGran_2\n")
|
||
);
|
||
goto CmBattGetBifDataExit;
|
||
}
|
||
|
||
RtlZeroMemory (&BifBuf->ModelNumber[0], CM_MAX_STRING_LENGTH);
|
||
argument = ACPI_METHOD_NEXT_ARGUMENT( argument );
|
||
status = GetStringElement (argument, &BifBuf->ModelNumber[0]);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBifData: Failed to get ModelNumber\n")
|
||
);
|
||
goto CmBattGetBifDataExit;
|
||
}
|
||
|
||
RtlZeroMemory (&BifBuf->SerialNumber[0], CM_MAX_STRING_LENGTH);
|
||
argument = ACPI_METHOD_NEXT_ARGUMENT( argument );
|
||
status = GetStringElement (argument, &BifBuf->SerialNumber[0]);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBifData: Failed to get SerialNumber\n")
|
||
);
|
||
goto CmBattGetBifDataExit;
|
||
}
|
||
|
||
RtlZeroMemory (&BifBuf->BatteryType[0], CM_MAX_STRING_LENGTH);
|
||
argument = ACPI_METHOD_NEXT_ARGUMENT( argument );
|
||
status = GetStringElement (argument, &BifBuf->BatteryType[0]);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBifData: Failed to get BatteryType\n")
|
||
);
|
||
goto CmBattGetBifDataExit;
|
||
}
|
||
|
||
RtlZeroMemory (&BifBuf->OEMInformation[0], CM_MAX_STRING_LENGTH);
|
||
argument = ACPI_METHOD_NEXT_ARGUMENT( argument );
|
||
|
||
//
|
||
// This returns an ASCIIZ string normally,
|
||
// but returns integer 0x00 if OEMInformation isn't supported.
|
||
//
|
||
if (argument->Type == ACPI_METHOD_ARGUMENT_INTEGER) {
|
||
if (argument->Argument != 0) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBifData: Failed to get OEMInformation\n")
|
||
);
|
||
goto CmBattGetBifDataExit;
|
||
}
|
||
BifBuf->OEMInformation[0] = 0;
|
||
status = STATUS_SUCCESS;
|
||
} else {
|
||
status = GetStringElement (argument, &BifBuf->OEMInformation[0]);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBifData: OEMInformation not supported\n")
|
||
);
|
||
}
|
||
}
|
||
|
||
CmBattGetBifDataExit:
|
||
//
|
||
// Done
|
||
//
|
||
ExFreePool (outputBuffer);
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
CmBattGetBstData(
|
||
IN PCM_BATT CmBatt,
|
||
OUT PCM_BST_BAT_INFO BstBuf
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Called to read the BST package from ACPI
|
||
|
||
Arguments:
|
||
|
||
CmBatt - The extension for this device.
|
||
BstBuf - Output buffer for the BST data
|
||
|
||
Return Value:
|
||
|
||
NT Status of the operation
|
||
|
||
--*/
|
||
{
|
||
ACPI_EVAL_INPUT_BUFFER inputBuffer;
|
||
NTSTATUS status;
|
||
PACPI_EVAL_OUTPUT_BUFFER outputBuffer;
|
||
PACPI_METHOD_ARGUMENT argument;
|
||
|
||
CmBattPrint(
|
||
CMBATT_CM_EXE,
|
||
("CmBattGetBstData: Buffer (0x%x) Device %x Tid %x\n",
|
||
BstBuf, CmBatt->DeviceNumber, GetTid() )
|
||
);
|
||
|
||
//
|
||
// Allocate a buffer for this
|
||
//
|
||
outputBuffer = ExAllocatePoolWithTag(
|
||
PagedPool,
|
||
EXPECTED_DATA_SIZE,
|
||
'MtaB'
|
||
);
|
||
if (!outputBuffer) {
|
||
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE),
|
||
("CmBattGetBstData: Failed to allocate Buffer\n")
|
||
);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
//
|
||
// Clear the buffers
|
||
//
|
||
RtlZeroMemory(outputBuffer, EXPECTED_DATA_SIZE);
|
||
RtlZeroMemory(BstBuf, sizeof(CM_BST_BAT_INFO));
|
||
|
||
//
|
||
// Set the request data
|
||
//
|
||
inputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
|
||
inputBuffer.MethodNameAsUlong = CM_BST_METHOD;
|
||
|
||
//
|
||
// Send the request along
|
||
//
|
||
status = CmBattSendDownStreamIrp(
|
||
CmBatt->LowerDeviceObject,
|
||
IOCTL_ACPI_EVAL_METHOD,
|
||
&inputBuffer,
|
||
sizeof(ACPI_EVAL_INPUT_BUFFER),
|
||
outputBuffer,
|
||
EXPECTED_DATA_SIZE
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBstData: Failed _BST method on device %x - Status (0x%x)\n",
|
||
CmBatt->DeviceNumber, status)
|
||
);
|
||
goto CmBattGetBstDataExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Sanity check the return value
|
||
//
|
||
if (outputBuffer->Signature != ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE ||
|
||
outputBuffer->Count != NUMBER_OF_BST_ELEMENTS) {
|
||
|
||
//
|
||
// Package did not contain the correct number of elements to be a BIF
|
||
//
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBstData: _BST returned %d elements. BIF requires %d\n",
|
||
outputBuffer->Count,
|
||
NUMBER_OF_BST_ELEMENTS)
|
||
);
|
||
status = STATUS_ACPI_INVALID_DATA;
|
||
goto CmBattGetBstDataExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Look at the return arguments
|
||
//
|
||
argument = outputBuffer->Argument;
|
||
|
||
//
|
||
// Parse the package data that is returned. This should look like:
|
||
//
|
||
status = GetDwordElement (argument, &BstBuf->BatteryState);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBstData: Failed to get BatteryState\n")
|
||
);
|
||
goto CmBattGetBstDataExit;
|
||
}
|
||
|
||
argument = ACPI_METHOD_NEXT_ARGUMENT( argument );
|
||
status = GetDwordElement (argument, &BstBuf->PresentRate);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBstData: Failed to get PresentRate\n")
|
||
);
|
||
goto CmBattGetBstDataExit;
|
||
}
|
||
|
||
argument = ACPI_METHOD_NEXT_ARGUMENT( argument );
|
||
status = GetDwordElement (argument, &BstBuf->RemainingCapacity);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBstData: Failed to get RemainingCapacity\n")
|
||
);
|
||
goto CmBattGetBstDataExit;
|
||
}
|
||
|
||
argument = ACPI_METHOD_NEXT_ARGUMENT( argument );
|
||
status = GetDwordElement (argument, &BstBuf->PresentVoltage);
|
||
if (!NT_SUCCESS (status)) {
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE | CMBATT_BIOS),
|
||
("CmBattGetBstData: Failed to get PresentVoltage\n")
|
||
);
|
||
goto CmBattGetBstDataExit;
|
||
}
|
||
|
||
CmBattPrint ((CMBATT_TRACE | CMBATT_DATA | CMBATT_BIOS),
|
||
("CmBattGetBstData: (BST) State=%x Rate=%x Capacity=%x Volts=%x\n",
|
||
BstBuf->BatteryState, BstBuf->PresentRate,
|
||
BstBuf->RemainingCapacity, BstBuf->PresentVoltage));
|
||
|
||
//
|
||
// Done --- cleanup
|
||
//
|
||
|
||
CmBattGetBstDataExit:
|
||
ExFreePool( outputBuffer );
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
GetDwordElement (
|
||
IN PACPI_METHOD_ARGUMENT Argument,
|
||
OUT PULONG PDword
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine cracks the integer value from the argument and stores it
|
||
in the supplied pointer to a ULONG
|
||
|
||
Arguments:
|
||
|
||
Argument - Points to the argument to parse
|
||
PDword - Where to store the argument
|
||
|
||
Return Value:
|
||
|
||
NT Status of the operation
|
||
|
||
--*/
|
||
{
|
||
|
||
//
|
||
// Check to see if we have the right type of data
|
||
//
|
||
if (Argument->Type != ACPI_METHOD_ARGUMENT_INTEGER) {
|
||
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE),
|
||
("GetDwordElement: Object contained wrong data type - %d\n",
|
||
Argument->Type)
|
||
);
|
||
return STATUS_ACPI_INVALID_DATA;
|
||
|
||
}
|
||
|
||
//
|
||
// Copy the DWORD
|
||
//
|
||
*PDword = Argument->Argument;
|
||
|
||
//
|
||
// Success!
|
||
//
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
GetStringElement (
|
||
IN PACPI_METHOD_ARGUMENT Argument,
|
||
OUT PUCHAR PBuffer
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine cracks the string from the argument and stroes it in the
|
||
supplied pointer to a PUCHAR
|
||
|
||
Note: A buffer is allowed as well.
|
||
|
||
Arguments:
|
||
|
||
Argument - Points to the argument to parse
|
||
PBuffer - Pointer to storage for the string
|
||
|
||
Return Value:
|
||
|
||
NT Status of the operation
|
||
|
||
--*/
|
||
{
|
||
|
||
//
|
||
// Check to see if we have the right type of data
|
||
//
|
||
if (Argument->Type != ACPI_METHOD_ARGUMENT_STRING &&
|
||
Argument->Type != ACPI_METHOD_ARGUMENT_BUFFER) {
|
||
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE),
|
||
("GetStringElement: Object contained wrong data type - %d\n",
|
||
Argument->Type)
|
||
);
|
||
return STATUS_ACPI_INVALID_DATA;
|
||
|
||
}
|
||
|
||
//
|
||
// Check to see if the return buffer is long enough
|
||
//
|
||
if (Argument->DataLength >= CM_MAX_STRING_LENGTH) {
|
||
|
||
CmBattPrint(
|
||
(CMBATT_ERROR | CMBATT_CM_EXE),
|
||
("GetStringElement: return buffer not big enough - %d\n",
|
||
Argument->DataLength)
|
||
);
|
||
return STATUS_BUFFER_TOO_SMALL;
|
||
|
||
}
|
||
|
||
//
|
||
// Copy the string
|
||
//
|
||
RtlCopyMemory (PBuffer, Argument->Data, Argument->DataLength);
|
||
|
||
//
|
||
// Success
|
||
//
|
||
return STATUS_SUCCESS;
|
||
}
|