windows-nt/Source/XPSP1/NT/drivers/apm/apmbatt/i386/apmbpnp.c
2020-09-26 16:20:57 +08:00

600 lines
14 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}