windows-nt/Source/XPSP1/NT/base/busdrv/acpi/hidbatt/hidbattio.cpp
2020-09-26 16:20:57 +08:00

608 lines
21 KiB
C++

/*
* title: HidBattIOCT.cpp
*
* purpose: Contains misc ioctl handlers for status and query info mainly
*
* Initial checkin for the hid to battery class driver. This should be
* the same for both Win 98 and NT 5. Alpha level source. Requires
* modified composite battery driver and modified battery class driver for
* Windows 98 support
*
*/
#include "hidbatt.h"
/*++
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
HidBattIoControl(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
NTSTATUS ntStatus = STATUS_NOT_SUPPORTED;
CBatteryDevExt * pDevExt;
PIO_STACK_LOCATION irpSp;
HIDDebugBreak(HIDBATT_BREAK_ALWAYS);
irpSp = IoGetCurrentIrpStackLocation(pIrp);
HidBattPrint (HIDBATT_TRACE, ("HidBattIoctl = %x\n", irpSp->Parameters.DeviceIoControl.IoControlCode));
// PrintIoctl(irpSp->Parameters.DeviceIoControl.IoControlCode);
pDevExt = (CBatteryDevExt *) pDeviceObject->DeviceExtension;
if (NT_SUCCESS(IoAcquireRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag)))
{
if (pDevExt->m_pBattery &&
pDevExt->m_pBattery->m_pBatteryClass) {
ntStatus = BatteryClassIoctl (pDevExt->m_pBattery->m_pBatteryClass, pIrp);
}
IoReleaseRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag);
} else {
ntStatus = STATUS_DEVICE_REMOVED;
pIrp->IoStatus.Status = ntStatus;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
}
if (ntStatus == STATUS_NOT_SUPPORTED)
{
HidBattCallLowerDriver(ntStatus, pDevExt->m_pLowerDeviceObject, pIrp);
}
return ntStatus;
}
VOID
HidBattNotifyHandler (
IN PVOID pContext,
IN CUsage * pUsage
)
{
HIDDebugBreak(HIDBATT_BREAK_ALWAYS);
NTSTATUS ntStatus;
ULONG ulCapacityLimit = BATTERY_UNKNOWN_CAPACITY;
BOOL bResult;
HidBattPrint (HIDBATT_TRACE, ("HidBattNotifyHandler\n"));
// called by input routine whenever a value change is noted to
// a notificable usage
CBatteryDevExt * pDevExt = (CBatteryDevExt *) pContext;
HidBattPrint (HIDBATT_DATA, ("HidBattNotifyHandler: Usage: %x\n", pUsage->m_pProperties->m_Usage));
switch (pUsage->m_pProperties->m_Usage)
{
case REMAINING_CAPACITY_ID:
bResult = pDevExt->m_pBattery->GetSetValue(REMAINING_CAPACITY_LIMIT_INDEX,&ulCapacityLimit,FALSE);
// Only send notification when capacity drops below notify level.
if ((bResult) && (ulCapacityLimit != BATTERY_UNKNOWN_CAPACITY) && (pUsage->m_Value != BATTERY_UNKNOWN_CAPACITY)
&& (pUsage->m_Value > ulCapacityLimit)) {
HidBattPrint (HIDBATT_TRACE, ("HidBattNotifyHandler:Suppressing notify\n"));
break;
}
case AC_PRESENT_ID: // check for battery off/on line
case DISCHARGING_ID:
case CHARGING_ID:
case BELOW_REMAINING_CAPACITY_ID:
case SHUTDOWN_IMMINENT_ID:
{
pDevExt->m_pBattery->m_bIsCacheValid=FALSE;
if (NT_SUCCESS (IoAcquireRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag))) {
ntStatus = BatteryClassStatusNotify(
pDevExt->m_pBattery->m_pBatteryClass);
IoReleaseRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag);
}
break;
}
default: // nothing to notify
break;
}
return;
}
NTSTATUS
HidBattQueryTag (
IN PVOID pContext,
OUT PULONG pulBatteryTag
)
{
HIDDebugBreak(HIDBATT_BREAK_ALWAYS);
CBatteryDevExt * pDevExt = (CBatteryDevExt *) pContext;
if (!NT_SUCCESS(IoAcquireRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag)) )
{
return STATUS_NO_SUCH_DEVICE;
}
*pulBatteryTag = pDevExt->m_pBattery->m_Tag;
IoReleaseRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag);
return STATUS_SUCCESS;
}
NTSTATUS
HidBattSetStatusNotify (
IN PVOID pContext,
IN ULONG BatteryTag,
IN PBATTERY_NOTIFY pBatteryNotify
)
{
bool bResult;
ULONG CentiAmpSec;
ULONG ulValue;
HIDDebugBreak(HIDBATT_BREAK_ALWAYS);
HidBattPrint (HIDBATT_TRACE, ("HidBattSetStatusNotify \n"));
CBatteryDevExt * pDevExt = (CBatteryDevExt *) pContext;
CBattery * pBattery = pDevExt->m_pBattery;
HidBattPrint (HIDBATT_DEBUG, ("HidBattSetStatusNotify->PowerState = %x\n", pBatteryNotify->PowerState));
HidBattPrint (HIDBATT_DEBUG, ("HidBattSetStatusNotify->LowCapacity = %x\n", pBatteryNotify->LowCapacity));
HidBattPrint (HIDBATT_DEBUG, ("HidBattSetStatusNotify->HighCapacity = %x\n", pBatteryNotify->HighCapacity));
if (!NT_SUCCESS(IoAcquireRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag)))
{
return STATUS_NO_SUCH_DEVICE;
}
if (pBattery->m_Tag != BatteryTag) {
IoReleaseRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag);
return STATUS_NO_SUCH_DEVICE;
}
if ((pBatteryNotify->HighCapacity == BATTERY_UNKNOWN_CAPACITY) ||
(pBatteryNotify->LowCapacity == BATTERY_UNKNOWN_CAPACITY)) {
HidBattPrint (HIDBATT_DEBUG, ("HidBattSetStatusNotify failing because of BATTERY_UNKNOWN_CAPACITY.\n"));
IoReleaseRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag);
return STATUS_NOT_SUPPORTED;
}
// first check for relative or absolute
if(pBattery->m_bRelative)
{
ulValue = pBatteryNotify->LowCapacity; // done
} else
{
// first check if setting to zero so that can skip below formula
if(pBatteryNotify->LowCapacity == 0)
{
ulValue = 0;
} else
{
// first must covert value to whatever is being used by this HID device.
// currently we assume either MilliVolts consistant with battery class or
// AmpSecs consistant with power spec
ULONG ulUnit = pBattery->GetUnit(REMAINING_CAPACITY_INDEX);
if(ulUnit)
{
short sExponent;
ULONG lMilliVolts;
long milliWattHours,CentiWattHours,CentiWattSecs;
sExponent = pBattery->GetExponent(REMAINING_CAPACITY_INDEX);
// conversion from millWattHours to AmpSecs
// formula = mWHs / 1000 / 3600 / volts ^ exponent correction
lMilliVolts = pBattery->m_BatteryStatus.Voltage; // stored as MilliVolts
if (lMilliVolts == 0) {
HidBattPrint (HIDBATT_ERROR,
("HidBattSetStatusNotify: Error: voltage = 0, fudging with 24V.\n"));
lMilliVolts = 24000;
}
milliWattHours = pBatteryNotify->LowCapacity;
CentiWattHours = milliWattHours /10;
CentiWattSecs = CentiWattHours / 3600;
CentiAmpSec = (CentiWattSecs *1000)/ lMilliVolts;
ulValue = CorrectExponent(CentiAmpSec,-2,sExponent);
} else
{
ulValue = pBatteryNotify->LowCapacity;
}
} // end if LowCapacity
} // end if relative
// now set low
bResult = pBattery->GetSetValue(REMAINING_CAPACITY_LIMIT_INDEX,&ulValue,TRUE);
IoReleaseRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag);
return bResult ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
}
NTSTATUS
HidBattDisableStatusNotify (
IN PVOID pContext
)
{
HIDDebugBreak(HIDBATT_BREAK_ALWAYS);
CBatteryDevExt * pDevExt = (CBatteryDevExt *) pContext;
pDevExt->m_pBattery->m_pBatteryNotify = NULL; // remove notify procedure
return STATUS_SUCCESS;
}
/*++
Routine Description:
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.
--*/
NTSTATUS
HidBattQueryStatus (
IN PVOID pContext,
IN ULONG BatteryTag,
OUT PBATTERY_STATUS pBatteryStatus
)
{
HIDDebugBreak(HIDBATT_BREAK_ALWAYS);
CBatteryDevExt * pDevExt = (CBatteryDevExt *) pContext;
NTSTATUS ntStatus;
HidBattPrint (HIDBATT_TRACE, ("HidBattQueryStatus - Tag (%d)\n",
BatteryTag));
if (!NT_SUCCESS(IoAcquireRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag)) )
{
return STATUS_NO_SUCH_DEVICE;
}
if ((BatteryTag == BATTERY_TAG_INVALID) || (pDevExt->m_pBattery->m_Tag == BATTERY_TAG_INVALID)) {
ntStatus = STATUS_NO_SUCH_DEVICE;
} else {
RtlZeroMemory (pBatteryStatus, sizeof(BATTERY_STATUS));
ntStatus = pDevExt->m_pBattery->RefreshStatus();
if (NT_SUCCESS(ntStatus)) {
RtlCopyMemory (pBatteryStatus, &pDevExt->m_pBattery->m_BatteryStatus, sizeof(BATTERY_STATUS));
HidBattPrint (HIDBATT_DATA, ("HidBattQueryStatus - Data (%08x)(%08x)(%08x)(%08x)\n",
pBatteryStatus->PowerState,
pBatteryStatus->Capacity,
pBatteryStatus->Rate,
pBatteryStatus->Voltage ));
} else {
ntStatus = STATUS_NO_SUCH_DEVICE;
HidBattPrint (HIDBATT_DATA, ("HidBattQueryStatus - Error\n" ));
}
}
IoReleaseRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag);
return ntStatus;
}
/*++
Routine Description:
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 - Optional Parameter
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
HidBattQueryInformation (
IN PVOID Context,
IN ULONG BatteryTag,
IN BATTERY_QUERY_INFORMATION_LEVEL Level,
IN LONG AtRate OPTIONAL,
OUT PVOID Buffer,
IN ULONG BufferLength,
OUT PULONG ReturnedLength
)
{
CBatteryDevExt * pDevExt = (CBatteryDevExt *) Context;
ULONG ulResult;
NTSTATUS ntStatus;
PVOID pReturnBuffer;
ULONG ulReturnBufferLength;
WCHAR scratchBuffer[MAX_BATTERY_STRING_SIZE];
WCHAR buffer2[MAX_BATTERY_STRING_SIZE];
UNICODE_STRING tmpUnicodeString;
UNICODE_STRING unicodeString;
ANSI_STRING ansiString;
bool bResult;
BATTERY_REMAINING_SCALE ScalePtr[2];
ULONG ulReturn,ulNewValue;
ULONG ulEstTimeStub = 5;
HIDDebugBreak(HIDBATT_BREAK_ALWAYS);
HidBattPrint (HIDBATT_TRACE, ("HidBattQueryInformation - Tag (%d)\n",
BatteryTag));
if (!NT_SUCCESS(IoAcquireRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag)) )
{
return STATUS_NO_SUCH_DEVICE;
}
//
// If caller has the wrong ID give an error
//
if (BatteryTag == BATTERY_TAG_INVALID ||
pDevExt->m_pBattery->m_Tag == BATTERY_TAG_INVALID ||
BatteryTag != pDevExt->m_pBattery->m_Tag)
{
IoReleaseRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag);
return STATUS_NO_SUCH_DEVICE;
}
ulResult = 0;
pReturnBuffer = NULL;
ulReturnBufferLength = 0;
ntStatus = STATUS_SUCCESS;
CUString cUniqueID;
SHORT sExponent;
char * pTemp;
//
// Get the info requested
//
switch (Level) {
case BatteryInformation:
//
// This data structure is populated by CmBattVerifyStaticInfo
//
HidBattPrint (HIDBATT_TRACE, ("HidBattQueryInformation - Battery Info\n"));
pReturnBuffer = (PVOID) &pDevExt->m_pBattery->m_BatteryInfo;
ulReturnBufferLength = sizeof (pDevExt->m_pBattery->m_BatteryInfo);
break;
case BatteryGranularityInformation:
//
// Get the granularity from the static info structure
// This data structure is populated by CmBattVerifyStaticInfo
//
{
HidBattPrint (HIDBATT_TRACE, ("HidBattQueryInformation - Granularity\n"));
bResult = pDevExt->m_pBattery->GetSetValue(GRANULARITY1_INDEX, &ulReturn,FALSE);
if(!pDevExt->m_pBattery->m_bRelative)
{
// convert from amps to watts
sExponent = pDevExt->m_pBattery->GetExponent(GRANULARITY1_INDEX);
ulNewValue = CorrectExponent(ulReturn,sExponent,-2);
ulReturn= CentiAmpSecsToMilliWattHours(ulNewValue,pDevExt->m_pBattery->m_BatteryStatus.Voltage);
}
ScalePtr[0].Granularity = bResult ? ulReturn : 0;
bResult = pDevExt->m_pBattery->GetSetValue(GRANULARITY2_INDEX, &ulReturn,FALSE);
if(!pDevExt->m_pBattery->m_bRelative)
{
// convert from amps to watts
sExponent = pDevExt->m_pBattery->GetExponent(GRANULARITY2_INDEX);
ulNewValue = CorrectExponent(ulReturn,sExponent,-2);
ulReturn= CentiAmpSecsToMilliWattHours(ulNewValue,pDevExt->m_pBattery->m_BatteryStatus.Voltage);
}
ScalePtr[1].Granularity = bResult ? ulReturn : 0;
bResult = pDevExt->m_pBattery->GetSetValue(WARNING_CAPACITY_LIMIT_INDEX, &ulReturn,FALSE);
if(!pDevExt->m_pBattery->m_bRelative)
{
// convert from amps to watts
sExponent = pDevExt->m_pBattery->GetExponent(WARNING_CAPACITY_LIMIT_INDEX);
ulNewValue = CorrectExponent(ulReturn,sExponent,-2);
ulReturn= CentiAmpSecsToMilliWattHours(ulNewValue,pDevExt->m_pBattery->m_BatteryStatus.Voltage);
}
ScalePtr[0].Capacity = bResult ? ulReturn : 0;
bResult = pDevExt->m_pBattery->GetSetValue(DESIGN_CAPACITY_INDEX, &ulReturn,FALSE);
if(!pDevExt->m_pBattery->m_bRelative)
{
// convert from amps to watts
sExponent = pDevExt->m_pBattery->GetExponent(DESIGN_CAPACITY_INDEX);
ulNewValue = CorrectExponent(ulReturn,sExponent,-2);
ulReturn= CentiAmpSecsToMilliWattHours(ulNewValue,pDevExt->m_pBattery->m_BatteryStatus.Voltage);
}
ScalePtr[1].Capacity = bResult ? ulReturn : 0;
pReturnBuffer = ScalePtr;
ulReturnBufferLength = 2 * sizeof (BATTERY_REMAINING_SCALE);
}
break;
case BatteryTemperature:
HidBattPrint (HIDBATT_TRACE, ("HidBattQueryInformation - Temperature\n"));
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
break;
case BatteryEstimatedTime:
HidBattPrint (HIDBATT_TRACE, ("HidBattQueryInformation - Estimated time\n"));
bResult = pDevExt->m_pBattery->GetSetValue(RUNTIME_TO_EMPTY_INDEX, &ulReturn,FALSE);
if(!bResult)
{
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
} else
{
SHORT exponent;
exponent = pDevExt->m_pBattery->GetExponent(RUNTIME_TO_EMPTY_INDEX);
ulReturn = CorrectExponent (ulReturn, exponent, 0);
pReturnBuffer = &ulReturn;
ulReturnBufferLength = sizeof (ULONG);
}
break;
case BatteryDeviceName:
//
// Model Number must be returned as a wide string
//
HidBattPrint (HIDBATT_TRACE, ("HidBattQueryInformation - Device Name\n"));
if(pDevExt->m_pBattery->m_pProduct)
{
pReturnBuffer = pDevExt->m_pBattery->m_pProduct->m_String.Buffer;
ulReturnBufferLength = pDevExt->m_pBattery->m_pProduct->m_String.Length;
}
break;
case BatteryManufactureDate:
HidBattPrint (HIDBATT_TRACE, ("HidBattQueryInformation - Mfr Date\n"));
if(!pDevExt->m_pBattery->m_ManufactureDate.Day)
{
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
break;
}
pReturnBuffer = &pDevExt->m_pBattery->m_ManufactureDate;
ulReturnBufferLength = sizeof(pDevExt->m_pBattery->m_ManufactureDate);
break;
case BatteryManufactureName:
//
// Oem Info must be returned as wide string
//
HidBattPrint (HIDBATT_TRACE, ("HidBattQueryInformation - Mfr Name\n"));
if(pDevExt->m_pBattery->m_pManufacturer)
{
pReturnBuffer = pDevExt->m_pBattery->m_pManufacturer->m_String.Buffer;
ulReturnBufferLength = pDevExt->m_pBattery->m_pManufacturer->m_String.Length;
}
break;
case BatteryUniqueID:
//
// Concatenate the serial #, manufacturer name, and Product //
// start off with serial number
HidBattPrint (HIDBATT_TRACE, ("HidBattQueryInformation - Unique ID\n"));
if(pDevExt->m_pBattery->m_pSerialNumber) {
HidBattPrint (HIDBATT_TRACE, ("HidBattQueryInformation - Serial = %s\n", pDevExt->m_pBattery->m_pSerialNumber));
cUniqueID.Append(pDevExt->m_pBattery->m_pSerialNumber);
} else {
HidBattPrint (HIDBATT_TRACE, ("HidBattQueryInformation - Serial = NULL\n"));
CUString * pSTemp = new (NonPagedPool, HidBattTag) CUString(L"1000");
if (pSTemp) {
cUniqueID.Append(pSTemp);
delete pSTemp;
}
}
if(pDevExt->m_pBattery->m_pManufacturer)
cUniqueID.Append(pDevExt->m_pBattery->m_pManufacturer); // add mfr name
else
{
CUString * pSTemp = new (NonPagedPool, HidBattTag) CUString(L"Mfr");
if (pSTemp) {
cUniqueID.Append(pSTemp);
delete pSTemp;
}
}
if(pDevExt->m_pBattery->m_pProduct)
cUniqueID.Append(pDevExt->m_pBattery->m_pProduct); // add Product
else
{
CUString * pSTemp = new (NonPagedPool, HidBattTag) CUString(L"Prod");
if (pSTemp) {
cUniqueID.Append(pSTemp);
delete pSTemp;
}
}
pReturnBuffer = cUniqueID.m_String.Buffer;
ulReturnBufferLength = cUniqueID.m_String.Length;
break;
default:
HidBattPrint (HIDBATT_TRACE, ("HidBattQueryInformation - Default\n"));
ntStatus = STATUS_INVALID_PARAMETER;
break;
}
//
// Done, return buffer if needed
//
*ReturnedLength = ulReturnBufferLength;
if (BufferLength < ulReturnBufferLength) {
ntStatus = STATUS_BUFFER_TOO_SMALL;
}
if (NT_SUCCESS(ntStatus) && pReturnBuffer) {
RtlCopyMemory (Buffer, pReturnBuffer, ulReturnBufferLength); // Copy what's needed
}
HidBattPrint (HIDBATT_TRACE, ("HidBattQueryInformation - Status = %08x Buffer = %08x\n", ntStatus, *(PULONG)Buffer));
IoReleaseRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag);
return ntStatus;
}
NTSTATUS
HidBattIoCompletion(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp,
IN PVOID pdoIoCompletedEvent
)
{
HidBattPrint (HIDBATT_TRACE, ("HidBattIoCompletion\n"));
KeSetEvent((KEVENT *) pdoIoCompletedEvent,0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}