You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
575 lines
14 KiB
575 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Comppnp.c
|
|
|
|
Abstract:
|
|
|
|
Composite Battery PnP and power functions
|
|
|
|
Author:
|
|
|
|
Scott Brenden
|
|
|
|
Environment:
|
|
|
|
Notes:
|
|
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "compbatt.h"
|
|
|
|
#include <initguid.h>
|
|
#include <wdmguid.h>
|
|
#include <batclass.h>
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
CompBattPnpDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
IOCTL handler for the plug and play irps.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Battery for request
|
|
|
|
Irp - IO request
|
|
|
|
Return Value:
|
|
|
|
Status of request
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS status = STATUS_NOT_SUPPORTED;
|
|
PCOMPOSITE_BATTERY compBatt = (PCOMPOSITE_BATTERY)DeviceObject->DeviceExtension;
|
|
|
|
|
|
BattPrint (BATT_TRACE, ("CompBatt: ENTERING PnpDispatch\n"));
|
|
|
|
switch (irpStack->MinorFunction) {
|
|
|
|
case IRP_MN_START_DEVICE: {
|
|
//
|
|
// Register for Pnp notification of batteries coming and going
|
|
//
|
|
|
|
status = IoRegisterPlugPlayNotification(
|
|
EventCategoryDeviceInterfaceChange,
|
|
0,
|
|
(LPGUID)&GUID_DEVICE_BATTERY,
|
|
DeviceObject->DriverObject,
|
|
CompBattPnpEventHandler,
|
|
compBatt,
|
|
&compBatt->NotificationEntry
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
BattPrint (BATT_ERROR, ("CompBatt: Couldn't register for PnP notification - %x\n", status));
|
|
|
|
} else {
|
|
BattPrint (BATT_NOTE, ("CompBatt: Successfully registered for PnP notification\n"));
|
|
|
|
//
|
|
// Get the batteries that are already present in the system
|
|
//
|
|
|
|
status = CompBattGetBatteries (compBatt);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_PNP_DEVICE_STATE: {
|
|
//
|
|
// Prevent device from being manually uninstalled.
|
|
//
|
|
Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
case IRP_MN_STOP_DEVICE:
|
|
case IRP_MN_QUERY_STOP_DEVICE: {
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|
case IRP_MN_SURPRISE_REMOVAL: {
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Rules for handling PnP IRPs:
|
|
// 1) Don't change the status of any IRP we don't handle. We identify
|
|
// IRPs we don't handle via the code STATUS_NOT_SUPPORTED. This is
|
|
// the same code all PNP irps start out with, and as we are not allowed
|
|
// to fail IRPs with that code, it is the perfect choice to use this
|
|
// way.
|
|
// 2) Pass down all IRPs that we succeed or do not touch. Immediately
|
|
// complete any failures (excepting STATUS_NOT_SUPPORTED of course).
|
|
//
|
|
if (status != STATUS_NOT_SUPPORTED) {
|
|
|
|
Irp->IoStatus.Status = status;
|
|
}
|
|
|
|
if (NT_SUCCESS(status) || (status == STATUS_NOT_SUPPORTED)) {
|
|
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
status = IoCallDriver(compBatt->LowerDevice, Irp) ;
|
|
|
|
} else {
|
|
|
|
status = Irp->IoStatus.Status ;
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
BattPrint (BATT_TRACE, ("CompBatt: EXITING PnpDispatch\n"));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
CompBattPowerDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
IOCTL handler for the power irps.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Battery for request
|
|
|
|
Irp - IO request
|
|
|
|
Return Value:
|
|
|
|
Status of request
|
|
|
|
--*/
|
|
{
|
|
PCOMPOSITE_BATTERY compBatt = (PCOMPOSITE_BATTERY)DeviceObject->DeviceExtension;
|
|
|
|
BattPrint (BATT_TRACE, ("CompBatt: PowerDispatch recieved power IRP.\n"));
|
|
|
|
PoStartNextPowerIrp (Irp);
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
|
|
return PoCallDriver(compBatt->LowerDevice, Irp) ;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
CompBattPnpEventHandler(
|
|
IN PVOID NotificationStructure,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles Plug and Play event notifications. The only ones that
|
|
have been asked for are device interface changes associated with batteries,
|
|
so we will only receive notifications when batteries come and go (provided
|
|
they register their device interface).
|
|
|
|
Arguments:
|
|
|
|
NotificationStructure - This will be type PDEVICE_INTERFACE_CHANGE_NOTIFICATION
|
|
|
|
Context - The composite battery device extension
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_INTERFACE_CHANGE_NOTIFICATION changeNotification;
|
|
PCOMPOSITE_BATTERY compBatt;
|
|
|
|
BattPrint (BATT_TRACE, ("CompBatt: ENTERING PnpEventHandler\n"));
|
|
|
|
compBatt = (PCOMPOSITE_BATTERY) Context;
|
|
changeNotification = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION) NotificationStructure;
|
|
|
|
|
|
BattPrint(BATT_NOTE, ("CompBatt: Received device interface change notification\n"));
|
|
|
|
if (IsEqualGUID(&changeNotification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL)) {
|
|
|
|
BattPrint(BATT_NOTE, ("CompBatt: Received notification of battery arrival\n"));
|
|
CompBattAddNewBattery (changeNotification->SymbolicLinkName, compBatt);
|
|
|
|
} else if (IsEqualGUID(&changeNotification->Event, &GUID_DEVICE_INTERFACE_REMOVAL)) {
|
|
|
|
BattPrint (BATT_NOTE, ("CompBatt: Received notification of battery removal\n"));
|
|
|
|
//
|
|
// Nothing to do here. MonitorIrpComplete will do cleanup when it's requests fail
|
|
// with STATUS_DEVICE_REMOVED.
|
|
//
|
|
|
|
} else {
|
|
|
|
BattPrint (BATT_NOTE, ("CompBatt: Received unhandled PnP event\n"));
|
|
}
|
|
|
|
BattPrint (BATT_TRACE, ("CompBatt: EXITING PnpEventHandler\n"));
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
CompBattRemoveBattery(
|
|
IN PUNICODE_STRING SymbolicLinkName,
|
|
IN PCOMPOSITE_BATTERY CompBatt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine removes an existing battery from the list of batteries kept by the
|
|
composite battery.
|
|
|
|
Arguments:
|
|
|
|
SymbolicLinkName - Name used to check if battery is on list
|
|
and to close the battery if so.
|
|
|
|
CompBatt - Device extension for the composite battery
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PCOMPOSITE_ENTRY Battery;
|
|
|
|
// NonPaged code. This is called by an Irp completion routine.
|
|
|
|
BattPrint (BATT_TRACE, ("CompBatt: RemoveBattery\n"));
|
|
|
|
//
|
|
// Remove the battery from the list if it is there.
|
|
//
|
|
|
|
Battery = RemoveBatteryFromList (SymbolicLinkName, CompBatt);
|
|
|
|
if(!Battery) {
|
|
|
|
//
|
|
// removed ok if not on list
|
|
//
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Deallocate the Work Item.
|
|
//
|
|
|
|
ObDereferenceObject(Battery->DeviceObject);
|
|
|
|
ExFreePool (Battery);
|
|
|
|
// Invalidate cached Battery info and send notification
|
|
CompBatt->Info.Valid = 0;
|
|
BatteryClassStatusNotify (CompBatt->Class);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CompBattAddNewBattery(
|
|
IN PUNICODE_STRING SymbolicLinkName,
|
|
IN PCOMPOSITE_BATTERY CompBatt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine adds a new battery to the list of batteries kept by the
|
|
composite battery.
|
|
|
|
Arguments:
|
|
|
|
SymbolicLinkName - Name used to check if battery is already on list
|
|
and to open the battery if not.
|
|
|
|
CompBatt - Device extension for the composite battery
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PCOMPOSITE_ENTRY newBattery;
|
|
PUNICODE_STRING battName;
|
|
PFILE_OBJECT fileObject;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PIRP newIrp;
|
|
BOOLEAN onList;
|
|
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
BattPrint (BATT_TRACE, ("CompBatt: ENTERING AddNewBattery \"%w\" \n", SymbolicLinkName->Buffer));
|
|
|
|
//
|
|
// Lock the list and see if this new battery is on it
|
|
//
|
|
|
|
onList = IsBatteryAlreadyOnList (SymbolicLinkName, CompBatt);
|
|
|
|
if (!onList) {
|
|
|
|
//
|
|
// Create the node for the new battery
|
|
//
|
|
|
|
newBattery = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof (COMPOSITE_ENTRY) + SymbolicLinkName->Length,
|
|
'CtaB'
|
|
);
|
|
|
|
if (!newBattery) {
|
|
BattPrint (BATT_ERROR, ("CompBatt: Couldn't allocate new battery node\n"));
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto AddNewBatteryClean1;
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize the new battery
|
|
//
|
|
|
|
RtlZeroMemory (newBattery, sizeof (COMPOSITE_ENTRY));
|
|
|
|
newBattery->Info.Tag = BATTERY_TAG_INVALID;
|
|
newBattery->NewBatt = TRUE;
|
|
|
|
battName = &newBattery->BattName;
|
|
battName->MaximumLength = SymbolicLinkName->Length;
|
|
battName->Buffer = (PWCHAR)(battName + 1);
|
|
|
|
RtlCopyUnicodeString (battName, SymbolicLinkName);
|
|
|
|
|
|
//
|
|
// Get the device object.
|
|
//
|
|
|
|
status = CompBattGetDeviceObjectPointer(SymbolicLinkName,
|
|
FILE_ALL_ACCESS,
|
|
&fileObject,
|
|
&newBattery->DeviceObject
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
BattPrint (BATT_ERROR, ("CompBattAddNewBattery: Failed to get device Object. status = %lx\n", status));
|
|
goto AddNewBatteryClean2;
|
|
}
|
|
|
|
//
|
|
// Increment the reference count to the device object of the battery
|
|
//
|
|
|
|
ObReferenceObject(newBattery->DeviceObject);
|
|
|
|
//
|
|
// Decrement reference count to file handle,
|
|
// so batteries will not refuse removal requests.
|
|
//
|
|
|
|
ObDereferenceObject(fileObject);
|
|
|
|
//
|
|
// Allocate a status Irp for the new battery
|
|
//
|
|
|
|
newIrp = IoAllocateIrp ((UCHAR)(newBattery->DeviceObject->StackSize + 1), FALSE);
|
|
|
|
if (!newIrp) {
|
|
BattPrint (BATT_ERROR, ("CompBatt: Couldn't allocate new battery Irp\n"));
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto AddNewBatteryClean3;
|
|
}
|
|
|
|
newBattery->StatusIrp = newIrp;
|
|
|
|
|
|
//
|
|
// Setup control data on irp
|
|
//
|
|
|
|
irpSp = IoGetNextIrpStackLocation(newIrp);
|
|
irpSp->Parameters.Others.Argument1 = (PVOID) CompBatt;
|
|
irpSp->Parameters.Others.Argument2 = (PVOID) newBattery;
|
|
|
|
//
|
|
// Fill in irp so irp handler will re-dispatch it
|
|
//
|
|
|
|
IoSetNextIrpStackLocation (newIrp);
|
|
|
|
irpSp = IoGetNextIrpStackLocation(newIrp);
|
|
newIrp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
|
|
newBattery->State = CB_ST_GET_TAG;
|
|
|
|
CompbattInitializeDeleteLock (&newBattery->DeleteLock);
|
|
|
|
//
|
|
// Put Battery onthe battery list before starting the
|
|
// MonitorIrpComplete loop.
|
|
//
|
|
|
|
ExAcquireFastMutex (&CompBatt->ListMutex);
|
|
InsertTailList (&CompBatt->Batteries, &newBattery->Batteries);
|
|
ExReleaseFastMutex (&CompBatt->ListMutex);
|
|
|
|
//
|
|
// Initialize Work Item
|
|
//
|
|
|
|
ExInitializeWorkItem (&newBattery->WorkItem, CompBattMonitorIrpCompleteWorker, newBattery);
|
|
|
|
//
|
|
// Start Monitoring Battery
|
|
//
|
|
|
|
CompBattMonitorIrpComplete (newBattery->DeviceObject, newIrp, NULL);
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
goto AddNewBatteryClean1;
|
|
|
|
AddNewBatteryClean3:
|
|
ObDereferenceObject(newBattery->DeviceObject);
|
|
|
|
AddNewBatteryClean2:
|
|
ExFreePool (newBattery);
|
|
|
|
AddNewBatteryClean1:
|
|
|
|
BattPrint (BATT_TRACE, ("CompBatt: EXITING AddNewBattery\n"));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
CompBattGetBatteries(
|
|
IN PCOMPOSITE_BATTERY CompBatt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine uses the PnP manager to get all the batteries that have already
|
|
registered their interfaces (that we won't get notifications for) and then
|
|
adds them to the list of batteries.
|
|
|
|
Arguments:
|
|
|
|
CompBatt - Device extension for the composite battery
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING tmpString;
|
|
PWSTR stringPointer;
|
|
int i;
|
|
|
|
|
|
BattPrint (BATT_TRACE, ("CompBatt: ENTERING GetBatteries\n"));
|
|
|
|
//
|
|
// Call the PnP manager to get the list of devices already register for the
|
|
// battery class.
|
|
//
|
|
|
|
status = IoGetDeviceInterfaces(
|
|
&GUID_DEVICE_BATTERY,
|
|
NULL,
|
|
0,
|
|
&stringPointer
|
|
);
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
BattPrint (BATT_ERROR, ("CompBatt: Couldn't get list of batteries\n"));
|
|
|
|
} else {
|
|
//
|
|
// Now parse the list and try to add them to the composite battery list
|
|
//
|
|
|
|
i = 0;
|
|
RtlInitUnicodeString (&tmpString, &stringPointer[i]);
|
|
|
|
while (tmpString.Length) {
|
|
|
|
status = CompBattAddNewBattery (&tmpString, CompBatt);
|
|
i += (tmpString.Length / sizeof(WCHAR)) + 1;
|
|
RtlInitUnicodeString (&tmpString, &stringPointer[i]);
|
|
}
|
|
|
|
ExFreePool (stringPointer);
|
|
|
|
}
|
|
|
|
BattPrint (BATT_TRACE, ("CompBatt: EXITING GetBatteries\n"));
|
|
return status;
|
|
}
|
|
|
|
|
|
|