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

669 lines
20 KiB
C++

/*
* title: hidbatt.c
*
* purpose: wdm kernel client interface between HID class and power class
*
* 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"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,DriverEntry)
#endif
// Global
ULONG HidBattDebug = HIDBATT_PRINT_NEVER;
USHORT HidBreakFlag = HIDBATT_BREAK_NEVER;
USHORT gusInstance = 0;
//
// Device Names
//
#define HidBattDeviceName L"\\Device\\HIDBattery"
// local protos
NTSTATUS
HidBattSystemControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
NTSTATUS status;
HidBattPrint (HIDBATT_TRACE, ("HidBatt:DriverEntry\n"));
HIDDebugBreak(HIDBATT_BREAK_FULL);
/************************************************************************************/
/* */
/* fill in the slots for the functions in */
/* the Driver object. */
/* */
/************************************************************************************/
DriverObject->MajorFunction[IRP_MJ_CREATE] = HidBattOpen;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = HidBattClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HidBattIoControl;
DriverObject->MajorFunction[IRP_MJ_POWER] = HidBattPowerDispatch;
DriverObject->MajorFunction[IRP_MJ_PNP] = HidBattPnpDispatch;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HidBattSystemControl; // pass down to hid class
DriverObject->DriverUnload = HidBattUnload; // this is unloadable with current rev of battery class
DriverObject->DriverExtension->AddDevice = HidBattAddDevice;
return STATUS_SUCCESS;
}
NTSTATUS
HidBattAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT pHidPdo
)
{
BOOL bResult;
PUNICODE_STRING unicodeString;
PDEVICE_OBJECT pBatteryFdo = NULL;
NTSTATUS ntStatus;
CBatteryDevExt * pDevExt;
UNICODE_STRING numberString;
WCHAR numberBuffer[10];
CUString * pBatteryName;
// enters here with pdo of hidclass - power class object
HIDDebugBreak(HIDBATT_BREAK_ALWAYS);
HidBattPrint (HIDBATT_TRACE, ("HidBattAddDevice\n"));
/* sberard - Removed due to changes in hidclass.sys (bug #274422)
HID_COLLECTION_INFORMATION HidInfo;
RtlZeroMemory(&HidInfo,sizeof(HID_COLLECTION_INFORMATION));
ntStatus = DoIoctl(
pHidPdo,
IOCTL_HID_GET_COLLECTION_INFORMATION,
NULL,
0,
&HidInfo,
sizeof(HID_COLLECTION_INFORMATION),
(CHidDevice *) NULL
);
if(NT_ERROR(ntStatus))
{
HidBattPrint (HIDBATT_ERROR_ONLY, ("HidBattAddDevice: IOCTL_HID_GET_COLLECTION_INFORMATION failed 0x%08x\n", ntStatus));
return STATUS_UNSUCCESSFUL;
}
*/
// too early to communicate with device, stash hid pdo and complete
pBatteryName = new (NonPagedPool, HidBattTag) CUString(HidBattDeviceName);
if (!pBatteryName) {
return STATUS_INSUFFICIENT_RESOURCES;
}
// Create the UPS PDO device name based on the battery instance
//
CUString * pInstanceNumber = new (NonPagedPool, HidBattTag) CUString(++gusInstance,10);
if (!pInstanceNumber) {
return STATUS_INSUFFICIENT_RESOURCES;
}
pBatteryName->Append(&pInstanceNumber->m_String);
delete pInstanceNumber;
ntStatus = IoCreateDevice(
DriverObject,
sizeof (CBatteryDevExt),
&pBatteryName->m_String,
FILE_DEVICE_BATTERY,
0,
FALSE,
&pBatteryFdo
);
if (ntStatus != STATUS_SUCCESS) {
HidBattPrint(HIDBATT_ERROR, ("HidBattCreateFdo: error (0x%x) creating device object\n", ntStatus));
delete pBatteryName;
--gusInstance; // reflect loss of device to instance
return(ntStatus);
}
// pBatteryFdo->DeviceExtension = new (NonPagedPool, HidBattTag) CBatteryDevExt;
// pBatteryFdo->StackSize++; // add one stack entry for battery class
// layer the battery pdo to the hid class pdo
// so that we begin to receive the device irps
PDEVICE_OBJECT pHidDeviceObject = IoAttachDeviceToDeviceStack(pBatteryFdo,pHidPdo);
pDevExt = (CBatteryDevExt *) pBatteryFdo->DeviceExtension;
pDevExt->m_RegistryPath.Length = 0;
pDevExt->m_RegistryPath.MaximumLength = sizeof(pDevExt->m_RegistryBuffer);
RtlZeroMemory(&pDevExt->m_RegistryBuffer, sizeof(pDevExt->m_RegistryBuffer));
pDevExt->m_RegistryPath.Buffer = &pDevExt->m_RegistryBuffer[0]; // set buffer pointer
pDevExt->m_pBattery = NULL;
pBatteryFdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
pBatteryFdo->Flags &= ~DO_DEVICE_INITIALIZING;
pDevExt->m_pHidPdo = pHidPdo;
pDevExt->m_pBatteryFdo = pBatteryFdo;
pDevExt->m_pLowerDeviceObject = pHidDeviceObject;
pDevExt->m_eExtType = eBatteryDevice;
pDevExt->m_bFirstStart = TRUE;
pDevExt->m_bJustStarted = FALSE;
pDevExt->m_ulDefaultAlert1 = (ULONG)-1;
pDevExt->m_pBatteryName = pBatteryName;
IoInitializeRemoveLock (&pDevExt->m_RemoveLock, HidBattTag, 10, 20);
IoInitializeRemoveLock (&pDevExt->m_StopLock, HidBattTag, 10, 20);
IoAcquireRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag);
IoReleaseRemoveLockAndWait (&pDevExt->m_StopLock, (PVOID) HidBattTag);
return STATUS_SUCCESS;
}
NTSTATUS
HidBattOpen(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION irpSp;
HIDDebugBreak(HIDBATT_BREAK_ALWAYS);
HidBattPrint (HIDBATT_TRACE, ("HidBattOpen\n"));
CBatteryDevExt * pDevExt = (CBatteryDevExt *) pDeviceObject->DeviceExtension;
if (NT_SUCCESS (IoAcquireRemoveLock (&pDevExt->m_RemoveLock, (PVOID) HidBattTag))) {
IoSkipCurrentIrpStackLocation (pIrp);
ntStatus = IoCallDriver(pDevExt->m_pLowerDeviceObject, pIrp);
HidBattPrint (HIDBATT_NOTE, ("HidBattOpen: lower driver returned 0x%08x\n", ntStatus));
IoReleaseRemoveLock (&pDevExt->m_RemoveLock, (PVOID) HidBattTag);
} else {
ntStatus = STATUS_NO_SUCH_DEVICE;
pIrp->IoStatus.Status = ntStatus;
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
}
return ntStatus;
}
NTSTATUS
HidBattClose(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION irpSp;
HidBattPrint (HIDBATT_TRACE, ("HidBattClose\n"));
// get the device extension
CBatteryDevExt * pDevExt = (CBatteryDevExt *) pDeviceObject->DeviceExtension;
HidBattCallLowerDriver(ntStatus, pDevExt->m_pLowerDeviceObject, pIrp);
HidBattPrint (HIDBATT_NOTE, ("HidBattClose: lower driver returned 0x%08x\n", ntStatus));
return ntStatus;
}
NTSTATUS
HidBattSystemControl(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
HidBattPrint (HIDBATT_TRACE, ("HidBattSystemControl\n"));
HIDDebugBreak(HIDBATT_BREAK_ALWAYS);
// all system control calls are passed down for now.
NTSTATUS ntStatus = STATUS_SUCCESS;
CBatteryDevExt * pDevExt = (CBatteryDevExt *) pDeviceObject->DeviceExtension;
HidBattCallLowerDriver(ntStatus,pDevExt->m_pLowerDeviceObject,pIrp);
return ntStatus;
}
VOID
HidBattUnload(
IN PDRIVER_OBJECT pDriverObject
)
{
HIDDebugBreak(HIDBATT_BREAK_ALWAYS);
// we can just return, no driver-only (non-device) resources were allocated
return;
}
NTSTATUS
HidBattPnpDispatch(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
/*++
Routine Description:
This routine is the dispatch routine for plug and play requests.
Arguments:
DeviceObject - Pointer to class device object.
Irp - Pointer to the request packet.
Return Value:
Status is returned.
--*/
HIDDebugBreak(HIDBATT_BREAK_ALWAYS);
PIO_STACK_LOCATION pIrpStack;
CBatteryDevExt * pDevExt;
NTSTATUS ntStatus;
BOOLEAN lockReleased = FALSE;
// PAGED_CODE();
ntStatus = STATUS_NOT_SUPPORTED;
//
// Get a pointer to the current parameters for this request. The
// information is contained in the current stack location.
//
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
pDevExt = (CBatteryDevExt *) pDeviceObject->DeviceExtension;
IoAcquireRemoveLock (&pDevExt->m_RemoveLock, (PVOID) HidBattTag);
//
// Dispatch minor function
//
switch (pIrpStack->MinorFunction)
{
case IRP_MN_STOP_DEVICE:
{
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_STOP_DEVICE\n"));
ntStatus = HidBattStopDevice(pDeviceObject, pIrp);
break;
} // IRP_MN_STOP_DEVICE
case IRP_MN_QUERY_DEVICE_RELATIONS:
{
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_QUERY_DEVICE_RELATIONS - type (%d)\n",
pIrpStack->Parameters.QueryDeviceRelations.Type));
break;
} // IRP_MN_QUERY_DEVICE_RELATIONS
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
{
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_FILTER_RESOURCE_REQUIREMENTS - type (%d)\n",
pIrpStack->Parameters.QueryDeviceRelations.Type));
break;
} // IRP_MN_FILTER_RESOURCE_REQUIREMENTS
case IRP_MN_REMOVE_DEVICE:
{
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_REMOVE_DEVICE\n"));
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: Waiting to remove\n"));
IoReleaseRemoveLockAndWait (&pDevExt->m_RemoveLock, (PVOID) HidBattTag);
lockReleased = TRUE;
// then remove device from device stack
IoDetachDevice(pDevExt->m_pLowerDeviceObject);
// delete our device
IoDeleteDevice(pDeviceObject);
ntStatus = STATUS_SUCCESS;
break;
} // IRP_MN_REMOVE_DEVICE
case IRP_MN_SURPRISE_REMOVAL:
case IRP_MN_QUERY_REMOVE_DEVICE:
{
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_QUERY_REMOVE_DEVICE\n"));
ntStatus = HidBattStopDevice(pDeviceObject, pIrp);
ntStatus = STATUS_SUCCESS;
break;
} // IRP_MN_QUERY_REMOVE_DEVICE
case IRP_MN_START_DEVICE:
{
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_START_DEVICE\n"));
if (pDevExt->m_bFirstStart) {
pDevExt->m_bJustStarted = TRUE;
pDevExt->m_bFirstStart = FALSE;
ntStatus = STATUS_SUCCESS;
break;
}
// else fall through and do the same thing as the cancel remove.
} // IRP_MN_START_DEVICE
case IRP_MN_CANCEL_REMOVE_DEVICE:
{
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_CANCEL_REMOVE_DEVICE\n"));
KEVENT cancelRemoveComplete;
KeInitializeEvent(&cancelRemoveComplete, SynchronizationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext (pIrp);
IoSetCompletionRoutine (pIrp, HidBattIoCompletion, &cancelRemoveComplete, TRUE, TRUE, TRUE);
pIrp->IoStatus.Status = STATUS_SUCCESS;
ntStatus = IoCallDriver (pDevExt->m_pLowerDeviceObject, pIrp);
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_CANCEL_REMOVE_DEVICE, Lower driver status: %08x\n", ntStatus));
if (ntStatus == STATUS_PENDING) {
KeWaitForSingleObject (&cancelRemoveComplete, Executive, KernelMode, FALSE, NULL);
ntStatus = pIrp->IoStatus.Status;
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_CANCEL_REMOVE_DEVICE, Lower driver 2nd status: %08x\n", ntStatus));
}
if (NT_SUCCESS (ntStatus)) {
ntStatus = HidBattInitializeDevice (pDeviceObject, pIrp);
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_CANCEL_REMOVE_DEVICE, Our status: %08x\n", ntStatus));
}
pIrp->IoStatus.Status = ntStatus;
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
IoReleaseRemoveLock (&pDevExt->m_RemoveLock, (PVOID) HidBattTag);
return ntStatus;
} // IRP_MN_CANCEL_REMOVE_DEVICE
case IRP_MN_QUERY_STOP_DEVICE:
{
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_QUERY_STOP_DEVICE\n"));
ntStatus = STATUS_SUCCESS;
break;
} // IRP_MN_QUERY_STOP_DEVICE
case IRP_MN_CANCEL_STOP_DEVICE:
{
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_CANCEL_STOP_DEVICE\n"));
ntStatus = STATUS_SUCCESS;
break;
} // IRP_MN_CANCEL_STOP_DEVICE
case IRP_MN_QUERY_RESOURCES:
{
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_QUERY_RESOURCES\n"));
break;
} // IRP_MN_QUERY_RESOURCES
case IRP_MN_READ_CONFIG:
{
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_READ_CONFIG\n"));
break;
} // IRP_MN_READ_CONFIG
case IRP_MN_WRITE_CONFIG:
{
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_WRITE_CONFIG\n"));
break;
} // IRP_MN_WRITE_CONFIG
case IRP_MN_EJECT:
{
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_EJECT\n"));
break;
} // IRP_MN_EJECT
case IRP_MN_SET_LOCK:
{
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_SET_LOCK\n"));
break;
} // IRP_MN_SET_LOCK
case IRP_MN_QUERY_ID:
{
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_QUERY_ID\n"));
break;
} // IRP_MN_QUERY_ID
case IRP_MN_QUERY_CAPABILITIES:
{
PDEVICE_CAPABILITIES deviceCaps;
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_QUERY_CAPABILITIES\n"));
deviceCaps = pIrpStack->Parameters.DeviceCapabilities.Capabilities;
deviceCaps->Removable = TRUE;
deviceCaps->SurpriseRemovalOK = TRUE;
ntStatus = STATUS_SUCCESS;
break;
} // IRP_MN_QUERY_CAPABILITIES
case IRP_MN_QUERY_PNP_DEVICE_STATE:
{
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: IRP_MN_PNP_DEVICE_STATE\n"));
if (pDevExt->m_bJustStarted == TRUE) {
pDevExt->m_bJustStarted = FALSE;
ntStatus = HidBattInitializeDevice (pDeviceObject, pIrp);
}
if (!NT_SUCCESS (ntStatus)) {
HidBattPrint (HIDBATT_PNP, ("HidBattPnpDispatch: HidBattInitializeDevice failed %0x\n", ntStatus));
pIrp->IoStatus.Information |= PNP_DEVICE_FAILED;
pIrp->IoStatus.Status = STATUS_SUCCESS;
}
break;
} // IRP_MN_PNP_DEVICE_STATE
default:
{
HidBattPrint (HIDBATT_PNP,
("HidBattPnpDispatch: Unimplemented minor %0x\n",
pIrpStack->MinorFunction));
break;
}
}
if (ntStatus != STATUS_NOT_SUPPORTED) {
pIrp->IoStatus.Status = ntStatus;
}
if (NT_SUCCESS(ntStatus) || (ntStatus == STATUS_NOT_SUPPORTED)) {
HidBattCallLowerDriver (ntStatus, pDevExt->m_pLowerDeviceObject, pIrp);
} else {
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
}
if (lockReleased == FALSE) {
IoReleaseRemoveLock (&pDevExt->m_RemoveLock, (PVOID) HidBattTag);
}
return ntStatus;
}
NTSTATUS
HidBattPowerDispatch(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
/*++
Routine Description:
This routine is the dispatch routine for power requests.
Arguments:
DeviceObject - Pointer to class device object.
Irp - Pointer to the request packet.
Return Value:
Status is returned.
--*/
{
PIO_STACK_LOCATION pIrpStack;
CBatteryDevExt * pDevExt;
NTSTATUS ntStatus;
HIDDebugBreak(HIDBATT_BREAK_ALWAYS);
// PAGED_CODE();
HidBattPrint ((HIDBATT_TRACE | HIDBATT_POWER), ("HidBattPowerDispatch\n"));
//
// Never fail a power IRP, even if we don't do anything.
//
ntStatus = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
//
// Get a pointer to the current parameters for this request. The
// information is contained in the current stack location.
//
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
pDevExt = (CBatteryDevExt *) pDeviceObject->DeviceExtension;
//
// Dispatch minor function
//
// this switch currently does no dispatches, and is expanded only for
// documentary purposes
switch (pIrpStack->MinorFunction) {
case IRP_MN_WAIT_WAKE: {
HidBattPrint (HIDBATT_POWER, ("HidBattPowerDispatch: IRP_MN_WAIT_WAKE\n"));
break;
}
case IRP_MN_POWER_SEQUENCE: {
HidBattPrint (HIDBATT_POWER, ("HidBattPowerDispatch: IRP_MN_POWER_SEQUENCE\n"));
break;
}
case IRP_MN_SET_POWER: {
HidBattPrint (HIDBATT_POWER, ("HidBattPowerDispatch: IRP_MN_SET_POWER\n"));
if (pIrpStack->Parameters.Power.Type == SystemPowerState &&
pIrpStack->Parameters.Power.State.SystemState >= PowerSystemShutdown) {
if (NT_SUCCESS(IoAcquireRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag)) )
{
//
// Write default RemainingCapcitylimit back to UPS so when the system reboots,
// the data returned by the device will be correct.
//
pDevExt->m_pBattery->GetSetValue(REMAINING_CAPACITY_LIMIT_INDEX,
&pDevExt->m_ulDefaultAlert1,TRUE);
IoReleaseRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag);
}
}
break;
}
case IRP_MN_QUERY_POWER: {
HidBattPrint (HIDBATT_POWER, ("HidBattPowerDispatch: IRP_MN_QUERY_POWER\n"));
break;
}
default: {
HidBattPrint(HIDBATT_LOW, ("HidBattPowerDispatch: minor %d\n",
pIrpStack->MinorFunction));
break;
}
}
PoStartNextPowerIrp(pIrp); // inform system we are done with this irp
IoSkipCurrentIrpStackLocation(pIrp);
ntStatus = PoCallDriver(pDevExt->m_pLowerDeviceObject,pIrp);
return ntStatus;
}
NTSTATUS HidBattSetInformation(
IN PVOID Context,
IN ULONG BatteryTag,
IN BATTERY_SET_INFORMATION_LEVEL Level,
IN PVOID Buffer OPTIONAL
)
{
/*
Routine Description:
Called by the class driver to set the battery's charge/discharge state.
The smart battery does not support the critical bias function of this
call.
Arguments:
Context - Miniport context value for battery
BatteryTag - Tag of current battery
Level - Action being asked for
Return Value:
NTSTATUS
--*/
// charge and discharge forcing not supported for UPS's
HidBattPrint (HIDBATT_TRACE, ("HidBattSetInformation\n"));
HIDDebugBreak(HIDBATT_BREAK_ALWAYS);
return STATUS_UNSUCCESSFUL;
}