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.
599 lines
15 KiB
599 lines
15 KiB
|
|
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
apmbpnp.c
|
|
|
|
Abstract:
|
|
|
|
Control Method Battery Plug and Play support
|
|
|
|
Author:
|
|
|
|
Ron Mosgrove
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "ApmBattp.h"
|
|
#include <initguid.h>
|
|
#include <wdmguid.h>
|
|
#include <ntapm.h>
|
|
|
|
//
|
|
// Device Names
|
|
//
|
|
PCWSTR ApmBattDeviceName = L"\\Device\\ApmBattery";
|
|
//PCWSTR AcAdapterName = L"\\Device\\AcAdapter";
|
|
|
|
//
|
|
// This is a special Hack as part of this general APM special hack
|
|
//
|
|
PVOID ApmGlobalClass = NULL;
|
|
|
|
//
|
|
// Prototypes
|
|
//
|
|
NTSTATUS
|
|
ApmBattAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT Pdo
|
|
);
|
|
|
|
NTSTATUS
|
|
ApmBattAddBattery(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT Pdo
|
|
);
|
|
|
|
#if 0
|
|
NTSTATUS
|
|
ApmBattAddAcAdapter(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT Pdo
|
|
);
|
|
#endif
|
|
|
|
NTSTATUS
|
|
ApmBattCreateFdo(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN ULONG DeviceId,
|
|
OUT PDEVICE_OBJECT *NewDeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
ApmBattCompleteRequest(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
ApmBattAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT Pdo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates functional device objects for each ApmBatt controller in the
|
|
system and attaches them to the physical device objects for the controllers
|
|
|
|
|
|
Arguments:
|
|
|
|
DriverObject - a pointer to the object for this driver
|
|
PhysicalDeviceObject - a pointer to the physical object we need to attach to
|
|
|
|
Return Value:
|
|
|
|
Status from device creation and initialization
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
ApmBattPrint (APMBATT_TRACE, ("ApmBattAddDevice\n"));
|
|
ASSERT(DeviceCount == 0);
|
|
|
|
if (DeviceCount != 0) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
DeviceCount = 1;
|
|
|
|
ApmBattPrint ((APMBATT_TRACE | APMBATT_PNP), ("ApmBattAddDevice: Entered with pdo %x\n", Pdo));
|
|
|
|
if (Pdo == NULL) {
|
|
|
|
//
|
|
// Have we been asked to do detection on our own?
|
|
// if so just return no more devices
|
|
//
|
|
ApmBattPrint((APMBATT_WARN | APMBATT_PNP), ("ApmBattAddDevice: Asked to do detection\n"));
|
|
return STATUS_NO_MORE_ENTRIES;
|
|
|
|
} else {
|
|
//
|
|
// This device is a control-method battery
|
|
//
|
|
return (ApmBattAddBattery (DriverObject, Pdo));
|
|
}
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ApmBattAddBattery(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT Pdo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a functional device object for a CM battery, and attache it
|
|
to the physical device object for the battery.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - a pointer to the object for this driver
|
|
PhysicalDeviceObject - a pointer to the physical object we need to attach to
|
|
|
|
Return Value:
|
|
|
|
Status from device creation and initialization
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_OBJECT Fdo = NULL;
|
|
PDEVICE_OBJECT lowerDevice = NULL;
|
|
PCM_BATT ApmBatt;
|
|
NTSTATUS Status;
|
|
BATTERY_MINIPORT_INFO BattInit;
|
|
ULONG uniqueId;
|
|
PNTAPM_LINK pparms;
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
|
|
PAGED_CODE();
|
|
|
|
ApmBattPrint ((APMBATT_TRACE | APMBATT_PNP), ("ApmBattAddBattery: pdo %x\n", Pdo));
|
|
//DbgBreakPoint();
|
|
|
|
uniqueId = 0;
|
|
|
|
//
|
|
// Create and initialize the new functional device object
|
|
//
|
|
Status = ApmBattCreateFdo(DriverObject, uniqueId, &Fdo);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
ApmBattPrint(APMBATT_ERROR, ("ApmBattAddBattery: error (0x%x) creating Fdo\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Initialize Fdo device extension data
|
|
//
|
|
|
|
ApmBatt = (PCM_BATT) Fdo->DeviceExtension;
|
|
ApmBatt->Fdo = Fdo;
|
|
ApmBatt->Pdo = Pdo;
|
|
|
|
//
|
|
// Layer our FDO on top of the PDO
|
|
//
|
|
|
|
lowerDevice = IoAttachDeviceToDeviceStack(Fdo,Pdo);
|
|
|
|
//
|
|
// No status. Do the best we can.
|
|
//
|
|
if (!lowerDevice) {
|
|
ApmBattPrint(APMBATT_ERROR, ("ApmBattAddBattery: Could not attach to lower device\n"));
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
ApmBatt->LowerDeviceObject = lowerDevice;
|
|
|
|
//
|
|
// Attach to the Class Driver
|
|
//
|
|
|
|
RtlZeroMemory (&BattInit, sizeof(BattInit));
|
|
BattInit.MajorVersion = BATTERY_CLASS_MAJOR_VERSION;
|
|
BattInit.MinorVersion = BATTERY_CLASS_MINOR_VERSION;
|
|
BattInit.Context = ApmBatt;
|
|
BattInit.QueryTag = ApmBattQueryTag;
|
|
BattInit.QueryInformation = ApmBattQueryInformation;
|
|
BattInit.SetInformation = NULL; // tbd
|
|
BattInit.QueryStatus = ApmBattQueryStatus;
|
|
BattInit.SetStatusNotify = ApmBattSetStatusNotify;
|
|
BattInit.DisableStatusNotify = ApmBattDisableStatusNotify;
|
|
|
|
BattInit.Pdo = Pdo;
|
|
BattInit.DeviceName = ApmBatt->DeviceName;
|
|
|
|
Status = BatteryClassInitializeDevice (&BattInit, &ApmBatt->Class);
|
|
ApmGlobalClass = ApmBatt->Class;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
//
|
|
// if we can't attach to class driver we're toast
|
|
//
|
|
ApmBattPrint(APMBATT_ERROR, ("ApmBattAddBattery: error (0x%x) registering with class\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// link up with APM driver (if we can't we're toast)
|
|
//
|
|
// Should be able to just call into Pdo.
|
|
//
|
|
// DO WORK HERE
|
|
//
|
|
Irp = IoAllocateIrp((CCHAR) (Pdo->StackSize+2), FALSE);
|
|
if (!Irp) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
IrpSp = IoGetNextIrpStackLocation(Irp);
|
|
IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
IrpSp->MinorFunction = 0;
|
|
IrpSp->DeviceObject = Pdo;
|
|
pparms = (PNTAPM_LINK) &(IrpSp->Parameters.Others);
|
|
pparms->Signature = NTAPM_LINK_SIGNATURE;
|
|
pparms->Version = NTAPM_LINK_VERSION;
|
|
pparms->BattLevelPtr = (ULONG)(&(NtApmGetBatteryLevel));
|
|
pparms->ChangeNotify = (ULONG)(&(ApmBattPowerNotifyHandler));
|
|
|
|
IoSetCompletionRoutine(Irp, ApmBattCompleteRequest, NULL, TRUE, TRUE, TRUE);
|
|
|
|
if (IoCallDriver(Pdo, Irp) != STATUS_SUCCESS) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//DbgPrint("apmbatt: NtApmGetBatteryLevel: %08lx\n", NtApmGetBatteryLevel);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
ApmBattCompleteRequest(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion routine for ioctl call to apm.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The target device which the request was sent
|
|
|
|
Irp - The irp completing
|
|
|
|
Context - The requestors completion routine
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
IoFreeIrp(Irp);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ApmBattCreateFdo(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN ULONG DeviceId,
|
|
OUT PDEVICE_OBJECT *NewFdo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will create and initialize a functional device object to
|
|
be attached to a Control Method Battery PDO.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - a pointer to the driver object this is created under
|
|
NewFdo - a location to store the pointer to the new device object
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if everything was successful
|
|
reason for failure otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PUNICODE_STRING unicodeString;
|
|
PDEVICE_OBJECT Fdo;
|
|
NTSTATUS Status;
|
|
PCM_BATT ApmBatt;
|
|
UNICODE_STRING numberString;
|
|
WCHAR numberBuffer[10];
|
|
|
|
PAGED_CODE();
|
|
|
|
ApmBattPrint ((APMBATT_TRACE | APMBATT_PNP), ("ApmBattCreateFdo, Battery Id=%x\n", DeviceId));
|
|
|
|
//
|
|
// Allocate the UNICODE_STRING for the device name
|
|
//
|
|
|
|
unicodeString = ExAllocatePoolWithTag (
|
|
PagedPool,
|
|
sizeof (UNICODE_STRING) + MAX_DEVICE_NAME_LENGTH,
|
|
'taBC'
|
|
);
|
|
|
|
if (!unicodeString) {
|
|
ApmBattPrint(APMBATT_ERROR, ("ApmBattCreateFdo: could not allocate unicode string\n"));
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
unicodeString->MaximumLength = MAX_DEVICE_NAME_LENGTH;
|
|
unicodeString->Length = 0;
|
|
unicodeString->Buffer = (PWCHAR) (unicodeString + 1);
|
|
|
|
//
|
|
// Create the PDO device name based on the battery instance
|
|
//
|
|
|
|
numberString.MaximumLength = 10;
|
|
numberString.Buffer = &numberBuffer[0];
|
|
|
|
RtlIntegerToUnicodeString (DeviceId, 10, &numberString);
|
|
RtlAppendUnicodeToString (unicodeString, (PWSTR) ApmBattDeviceName);
|
|
RtlAppendUnicodeToString (unicodeString, &numberString.Buffer[0]);
|
|
|
|
|
|
Status = IoCreateDevice(
|
|
DriverObject,
|
|
sizeof (CM_BATT),
|
|
unicodeString,
|
|
FILE_DEVICE_BATTERY,
|
|
0,
|
|
FALSE,
|
|
&Fdo
|
|
);
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
ApmBattPrint(APMBATT_ERROR, ("ApmBattCreateFdo: error (0x%x) creating device object\n", Status));
|
|
ExFreePool (unicodeString);
|
|
return(Status);
|
|
}
|
|
|
|
Fdo->Flags |= DO_BUFFERED_IO;
|
|
Fdo->Flags |= DO_POWER_PAGABLE; // Don't want power Irps at irql 2
|
|
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
Fdo->StackSize = 2;
|
|
|
|
//
|
|
// Initialize Fdo device extension data
|
|
//
|
|
|
|
ApmBatt = (PCM_BATT) Fdo->DeviceExtension;
|
|
RtlZeroMemory(ApmBatt, sizeof(CM_BATT));
|
|
ApmBatt->DeviceName = unicodeString;
|
|
ApmBatt->DeviceNumber = (USHORT) DeviceId;
|
|
ApmBatt->DeviceObject = Fdo;
|
|
*NewFdo = Fdo;
|
|
|
|
ApmBattPrint((APMBATT_TRACE | APMBATT_PNP), ("ApmBattCreateFdo: Created FDO %x\n", Fdo));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ApmBattPnpDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_STACK_LOCATION irpStack;
|
|
PCM_BATT ApmBatt;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
ApmBattPrint (APMBATT_TRACE, ("ApmBattPnpDispatch\n"));
|
|
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
//
|
|
// Get a pointer to the current parameters for this request. The
|
|
// information is contained in the current stack location.
|
|
//
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
ApmBatt = DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// Dispatch minor function
|
|
//
|
|
switch (irpStack->MinorFunction) {
|
|
|
|
case IRP_MN_START_DEVICE:
|
|
//
|
|
// if the Add succeeded, we are actually started...
|
|
//
|
|
ApmBattPrint (APMBATT_PNP, ("ApmBattPnpDispatch: IRP_MN_START_DEVICE\n"));
|
|
Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Status = Status;
|
|
ApmBattCallLowerDriver(Status, ApmBatt->LowerDeviceObject, Irp);
|
|
break;
|
|
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
ApmBattPrint (APMBATT_PNP, ("ApmBattPnpDispatch: IRP_MN_QUERY_DEVICE_RELATIONS - type (%d)\n",
|
|
irpStack->Parameters.QueryDeviceRelations.Type));
|
|
//
|
|
// Just pass it down
|
|
//
|
|
ApmBattCallLowerDriver(Status, ApmBatt->LowerDeviceObject, Irp);
|
|
break;
|
|
|
|
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
Status = Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
|
|
IoCompleteRequest(Irp, 0);
|
|
break;
|
|
|
|
default:
|
|
ApmBattPrint (APMBATT_PNP,
|
|
("ApmBattPnpDispatch: Unimplemented minor %0x\n",
|
|
irpStack->MinorFunction));
|
|
//
|
|
// Unimplemented minor, Pass this down to ACPI
|
|
//
|
|
ApmBattCallLowerDriver(Status, ApmBatt->LowerDeviceObject, Irp);
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ApmBattPowerDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
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 irpStack;
|
|
PCM_BATT ApmBatt;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
ApmBattPrint ((APMBATT_TRACE | APMBATT_POWER), ("ApmBattPowerDispatch\n"));
|
|
|
|
//
|
|
// Get a pointer to the current parameters for this request. The
|
|
// information is contained in the current stack location.
|
|
//
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
ApmBatt = DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// Dispatch minor function
|
|
//
|
|
switch (irpStack->MinorFunction) {
|
|
|
|
case IRP_MN_WAIT_WAKE:
|
|
ApmBattPrint (APMBATT_POWER, ("ApmBattPowerDispatch: IRP_MN_WAIT_WAKE\n"));
|
|
break;
|
|
|
|
case IRP_MN_POWER_SEQUENCE:
|
|
ApmBattPrint (APMBATT_POWER, ("ApmBattPowerDispatch: IRP_MN_POWER_SEQUENCE\n"));
|
|
break;
|
|
|
|
case IRP_MN_SET_POWER:
|
|
ApmBattPrint (APMBATT_POWER, ("ApmBattPowerDispatch: IRP_MN_SET_POWER\n"));
|
|
TagValue++;
|
|
break;
|
|
|
|
case IRP_MN_QUERY_POWER:
|
|
ApmBattPrint (APMBATT_POWER, ("ApmBattPowerDispatch: IRP_MN_QUERY_POWER\n"));
|
|
break;
|
|
|
|
default:
|
|
ApmBattPrint(APMBATT_LOW, ("ApmBattPowerDispatch: minor %d\n",
|
|
irpStack->MinorFunction));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// What do we do with the irp?
|
|
//
|
|
PoStartNextPowerIrp( Irp );
|
|
if (ApmBatt->LowerDeviceObject != NULL) {
|
|
|
|
//
|
|
// Forward the request along
|
|
//
|
|
IoSkipCurrentIrpStackLocation( Irp );
|
|
Status = PoCallDriver( ApmBatt->LowerDeviceObject, Irp );
|
|
|
|
} else {
|
|
|
|
//
|
|
// Complete the request with the current status
|
|
//
|
|
Status = Irp->IoStatus.Status;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|