📄 pnppower.c
字号:
//
// Build the selector information structure
//
// Adjust Number of Batteries to Match SelectorInfo Supported Batteries
// Just in case the ACPI information is incorrect
status = SmbBattBuildSelectorStruct (SubsystemFdo);
if (!NT_SUCCESS (status)) {
BattPrint(BAT_ERROR, ("SmbBattCreatePdos: couldn't talk to the selector\n"));
return status;
}
//
// Build device object for each battery
//
for (i = 0; i < subsystemExt->NumberOfBatteries; i++) {
//
// Create the device object
//
status = IoCreateDevice(
SubsystemFdo->DriverObject,
sizeof (SMB_BATT_PDO),
NULL,
FILE_DEVICE_BATTERY,
FILE_DEVICE_SECURE_OPEN|FILE_AUTOGENERATED_DEVICE_NAME,
FALSE,
&pdo
);
if (status != STATUS_SUCCESS) {
BattPrint(BAT_ERROR, ("SmbBattCreatePdos: error creating battery pdo %x\n", status));
//
// Make sure we don't later try to use devices that weren't created.
//
subsystemExt->NumberOfBatteries = i;
return(status);
}
//
// Initialize the Pdo
//
pdo->Flags |= DO_BUFFERED_IO;
pdo->Flags |= DO_POWER_PAGABLE;
//
// Save the PDO in the subsystem FDO PDO list
//
subsystemExt->BatteryPdoList[i] = pdo;
//
// Initialize the PDO extension
//
batteryPdoExt = (PSMB_BATT_PDO) pdo->DeviceExtension;
batteryPdoExt->SmbBattFdoType = SmbTypePdo;
batteryPdoExt->DeviceObject = pdo;
batteryPdoExt->BatteryNumber = i;
batteryPdoExt->SubsystemFdo = SubsystemFdo;
IoInitializeRemoveLock (&batteryPdoExt->RemoveLock,
SMB_BATTERY_TAG,
REMOVE_LOCK_MAX_LOCKED_MINUTES,
REMOVE_LOCK_HIGH_WATER_MARK);
//
// Device is ready for use
//
pdo->Flags &= ~DO_DEVICE_INITIALIZING;
} // for (i = 0; i < subsystemExt->NumberOfBatteries; i++)
return STATUS_SUCCESS;
}
NTSTATUS
SmbBattBuildDeviceRelations(
IN PSMB_BATT_SUBSYSTEM SubsystemExt,
IN PDEVICE_RELATIONS *DeviceRelations
)
/*++
Routine Description:
This routine is checks the device relations structure for existing device
relations, calculates how big a new device relations structure has to be,
allocates it, and fills it with the PDOs created for the batteries.
Arguments:
SubsystemExt - Device extension for the smart battery subsystem FDO
DeviceRelations - The Current DeviceRelations for the device...
Return Value:
NTSTATUS
--*/
{
PDEVICE_RELATIONS newDeviceRelations;
ULONG i, j;
ULONG newDeviceRelationsSize;
NTSTATUS status;
ULONG existingPdos = 0;
ULONG deviceRelationsSize = 0;
ULONG numberOfPdos = 0;
PAGED_CODE();
//
// Calculate the size the new device relations structure has to be
//
if (*DeviceRelations != NULL && (*DeviceRelations)->Count > 0) {
//
// There are existing device relations to be copied
//
existingPdos = (*DeviceRelations)->Count;
deviceRelationsSize = sizeof (ULONG) + (sizeof (PDEVICE_OBJECT) * existingPdos);
}
//
// Calculate the size needed for the new device relations structure and allocate it
//
numberOfPdos = existingPdos + SubsystemExt->NumberOfBatteries;
newDeviceRelationsSize = sizeof (ULONG) + (sizeof (PDEVICE_OBJECT) * numberOfPdos);
newDeviceRelations = ExAllocatePoolWithTag (PagedPool, newDeviceRelationsSize, 'StaB');
if (!newDeviceRelations) {
BattPrint (BAT_ERROR, ("SmbBattBuildDeviceRelations: couldn't allocate device relations buffer\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// If there are existing device relations copy them to the new device
// relations structure and free the old one.
//
if (existingPdos) {
RtlCopyMemory (newDeviceRelations, *DeviceRelations, deviceRelationsSize);
}
if (*DeviceRelations) { // Could be a zero length list, but still need freeing
ExFreePool (*DeviceRelations);
}
//
// Now add the battery PDOs to the end of the list and reference it
//
for (i = existingPdos, j = 0; i < numberOfPdos; i ++, j ++) {
newDeviceRelations->Objects[i] = SubsystemExt->BatteryPdoList[j];
status = ObReferenceObjectByPointer(
SubsystemExt->BatteryPdoList[j],
0,
NULL,
KernelMode
);
if (!NT_SUCCESS(status) ) {
//
// This should theoretically never happen...
//
BattPrint(BAT_ERROR, ("SmbBattBuildDeviceRelations: error referencing battery pdo %x\n", status));
return status;
}
}
newDeviceRelations->Count = numberOfPdos;
*DeviceRelations = newDeviceRelations;
return STATUS_SUCCESS;
}
NTSTATUS
SmbBattQueryDeviceRelations(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine handles the IRP_MN_QUERY_DEVICE_RELATIONS.
Arguments:
Pdo - Battery PDO
Irp - The query Irp
Return Value:
NTSTATUS
--*/
{
PSMB_NP_BATT SmbNPBatt = (PSMB_NP_BATT) DeviceObject->DeviceExtension;
PSMB_BATT_PDO PdoExt = (PSMB_BATT_PDO) DeviceObject->DeviceExtension;
PSMB_BATT_SUBSYSTEM SubsystemExt = (PSMB_BATT_SUBSYSTEM) DeviceObject->DeviceExtension;
PDEVICE_OBJECT pdo;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status = STATUS_NOT_SUPPORTED;
ULONG i;
PDEVICE_RELATIONS deviceRelations =
(PDEVICE_RELATIONS) Irp->IoStatus.Information;
PAGED_CODE();
BattPrint(BAT_TRACE, ("SmbBattQueryDeviceRelations: ENTERING\n"));
switch (SmbNPBatt->SmbBattFdoType) {
case SmbTypeSubsystem: {
if (IrpSp->Parameters.QueryDeviceRelations.Type == BusRelations) {
BattPrint(
BAT_IRPS,
("SmbBattQueryDeviceRelations: Handling Bus relations request\n")
);
if (SubsystemExt->NumberOfBatteries != 0) {
//
// We've already found our batteries, so we don't need to
// look again since smart batteries are static.
// Just rebuild the return structure.
//
status = SmbBattBuildDeviceRelations (SubsystemExt, &deviceRelations);
} else {
status = SmbBattCreatePdos (DeviceObject);
if (NT_SUCCESS (status)) {
status = SmbBattBuildDeviceRelations (SubsystemExt, &deviceRelations);
}
if (NT_SUCCESS (status)) {
//
// Now register for alarms
// (Used to register during START_DEVICE,
// but don't need notifications until after the batteries
// are here. This avoids some other problems too.)
status = SmbBattRegisterForAlarm (DeviceObject);
}
}
Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
}
break;
}
case SmbTypeBattery: {
status = STATUS_NOT_SUPPORTED;
break;
}
case SmbTypePdo: {
if (IrpSp->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation ) {
BattPrint(
BAT_IRPS,
("SmbBattQueryDeviceRelations: Handling TargetDeviceRelation request\n")
);
deviceRelations = ExAllocatePoolWithTag (PagedPool,
sizeof(DEVICE_RELATIONS),
SMB_BATTERY_TAG);
if (!deviceRelations) {
return STATUS_INSUFFICIENT_RESOURCES;
}
status = ObReferenceObjectByPointer(DeviceObject,
0,
NULL,
KernelMode);
if (!NT_SUCCESS(status)) {
ExFreePool(deviceRelations);
return status;
}
deviceRelations->Count = 1;
deviceRelations->Objects[0] = DeviceObject;
Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
} else {
status = STATUS_NOT_SUPPORTED;
}
break;
}
default: {
ASSERT (FALSE);
}
}
return status;
}
NTSTATUS
SmbBattRemoveDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine handles the IRP_MN_REMOVE_DEVICE.
Arguments:
Pdo - Battery PDO
Irp - The query Irp
Return Value:
NTSTATUS
--*/
{
PSMB_NP_BATT SmbNPBatt = (PSMB_NP_BATT) DeviceObject->DeviceExtension;
PSMB_BATT_PDO PdoExt = (PSMB_BATT_PDO) DeviceObject->DeviceExtension;
PSMB_BATT_SUBSYSTEM SubsystemExt = (PSMB_BATT_SUBSYSTEM) DeviceObject->DeviceExtension;
PDEVICE_OBJECT pdo;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status = STATUS_NOT_SUPPORTED;
ULONG i;
PAGED_CODE();
BattPrint(BAT_TRACE, ("SmbBattRemoveDevice: ENTERING\n"));
switch (SmbNPBatt->SmbBattFdoType) {
case SmbTypeSubsystem: {
BattPrint(BAT_IRPS, ("SmbBattRemoveDevice: Removing Subsystem FDO.\n"));
//
// De-register for notifications
//
SmbBattUnregisterForAlarm (DeviceObject);
IoFreeWorkItem (SubsystemExt->WorkerThread);
//
// Remove PDOs
//
for (i = 0; i < SubsystemExt->NumberOfBatteries; i++) {
pdo = SubsystemExt->BatteryPdoList[i];
if (pdo) {
PdoExt = (PSMB_BATT_PDO) pdo->DeviceExtension;
status = IoAcquireRemoveLock (&PdoExt->RemoveLock, Irp);
IoReleaseRemoveLockAndWait (&PdoExt->RemoveLock, Irp);
SubsystemExt->BatteryPdoList[i] = NULL;
IoDeleteDevice (pdo);
}
}
if ((SubsystemExt->SelectorPresent) && (SubsystemExt->Selector)) {
ExFreePool (SubsystemExt->Selector);
}
IoSkipCurrentIrpStackLocation (Irp);
Irp->IoStatus.Status = STATUS_SUCCESS;
status = IoCallDriver (SubsystemExt->LowerDevice, Irp);
IoDetachDevice (SubsystemExt->LowerDevice);
IoDeleteDevice (DeviceObject);
break;
}
case SmbTypeBattery: {
BattPrint(BAT_IRPS, ("SmbBattRemoveDevice: Removing Battery FDO\n"));
IoReleaseRemoveLockAndWait (&SmbNPBatt->RemoveLock, Irp);
//
// Unregister as a WMI Provider.
//
SmbBattWmiDeRegistration(SmbNPBatt);
//
// Tell the class driver we are going away
//
status = BatteryClassUnload (SmbNPBatt->Class);
ASSERT (NT_SUCCESS(status));
ExFreePool (SmbNPBatt->Batt);
((PSMB_BATT_PDO) SmbNPBatt->LowerDevice->DeviceExtension)->Fdo = NULL;
IoSkipCurrentIrpStackLocation (Irp);
Irp->IoStatus.Status = STATUS_SUCCESS;
status = IoCallDriver (SmbNPBatt->LowerDevice, Irp);
IoDetachDevice (SmbNPBatt->LowerDevice);
IoDeleteDevice (DeviceObject);
break;
}
case SmbTypePdo: {
BattPrint(BAT_IRPS, ("SmbBattRemoveDevice: Remove for Battery PDO (doing nothing)\n"));
//
// Don't delete the device until it is physically removed.
// Usually, the battery subsystem can't be physically removed...
//
//
// Need to release Remove lock, since PnP dispatch won't...
//
IoReleaseRemoveLock (&PdoExt->RemoveLock, Irp);
status = STATUS_SUCCESS;
//
// Complete the request with the current status
//
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
}
default: {
ASSERT (FALSE);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -