767 lines
20 KiB
C
767 lines
20 KiB
C
/*++
|
|
|
|
Copyright (c) 1997-1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
apmpnp.c
|
|
|
|
Abstract:
|
|
|
|
This module contains contains the plugplay calls
|
|
needed to make ntapm.sys work.
|
|
|
|
Author:
|
|
|
|
Bryan Willman
|
|
Kenneth D. Ray
|
|
Doron J. Holan
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include <wdm.h>
|
|
#include "ntapmp.h"
|
|
#include "ntapmdbg.h"
|
|
#include "ntapm.h"
|
|
//#include "stdio.h"
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
PDEVICE_OBJECT NtApm_ApmBatteryPdo = NULL;
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text (PAGE, NtApm_AddDevice)
|
|
#pragma alloc_text (PAGE, NtApm_PnP)
|
|
#pragma alloc_text (PAGE, NtApm_FDO_PnP)
|
|
#pragma alloc_text (PAGE, NtApm_PDO_PnP)
|
|
#pragma alloc_text (PAGE, NtApm_Power)
|
|
#pragma alloc_text (PAGE, NtApm_FDO_Power)
|
|
#pragma alloc_text (PAGE, NtApm_PDO_Power)
|
|
#pragma alloc_text (PAGE, NtApm_CreatePdo)
|
|
#pragma alloc_text (PAGE, NtApm_InitializePdo)
|
|
#endif
|
|
|
|
NTSTATUS
|
|
NtApm_AddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT BusPhysicalDeviceObject
|
|
)
|
|
/*++
|
|
Routine Description.
|
|
A bus has been found. Attach our FDO to it.
|
|
Allocate any required resources. Set things up. And be prepared for the
|
|
first ``start device.''
|
|
|
|
Arguments:
|
|
BusDeviceObject - Device object representing the bus. That to which we
|
|
attach a new FDO.
|
|
|
|
DriverObject - This very self referenced driver.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PDEVICE_OBJECT deviceObject;
|
|
PFDO_DEVICE_DATA deviceData;
|
|
UNICODE_STRING deviceNameUni;
|
|
PWCHAR deviceName;
|
|
ULONG nameLength;
|
|
|
|
PAGED_CODE ();
|
|
|
|
DrDebug(PNP_INFO, ("ntapm Add Device: 0x%x\n", BusPhysicalDeviceObject));
|
|
|
|
status = IoCreateDevice (
|
|
DriverObject, // our driver object
|
|
sizeof (FDO_DEVICE_DATA), // device object extension size
|
|
NULL, // FDOs do not have names
|
|
FILE_DEVICE_BUS_EXTENDER,
|
|
0, // No special characteristics
|
|
TRUE, // our FDO is exclusive
|
|
&deviceObject); // The device object created
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
return status;
|
|
}
|
|
|
|
deviceData = (PFDO_DEVICE_DATA) deviceObject->DeviceExtension;
|
|
RtlFillMemory (deviceData, sizeof (FDO_DEVICE_DATA), 0);
|
|
|
|
deviceData->IsFDO = TRUE;
|
|
deviceData->Self = deviceObject;
|
|
deviceData->UnderlyingPDO = BusPhysicalDeviceObject;
|
|
|
|
//
|
|
// Attach our filter driver to the device stack.
|
|
// the return value of IoAttachDeviceToDeviceStack is the top of the
|
|
// attachment chain. This is where all the IRPs should be routed.
|
|
//
|
|
// Our filter will send IRPs to the top of the stack and use the PDO
|
|
// for all PlugPlay functions.
|
|
//
|
|
deviceData->TopOfStack = IoAttachDeviceToDeviceStack (
|
|
deviceObject,
|
|
BusPhysicalDeviceObject
|
|
);
|
|
|
|
|
|
if (!deviceData->TopOfStack) {
|
|
IoDeleteDevice(deviceObject);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
status = ApmAddHelper();
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
IoDetachDevice(deviceData->TopOfStack);
|
|
IoDeleteDevice(deviceObject);
|
|
}
|
|
|
|
deviceObject->Flags |= DO_POWER_PAGABLE;
|
|
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NtApm_FDO_PnPComplete (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Pirp,
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
NtApm_PnP (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Answer the plithera of Irp Major PnP IRPS.
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION irpStack;
|
|
NTSTATUS status;
|
|
PCOMMON_DEVICE_DATA commonData;
|
|
KIRQL oldIrq;
|
|
|
|
PAGED_CODE ();
|
|
|
|
status = STATUS_SUCCESS;
|
|
irpStack = IoGetCurrentIrpStackLocation (Irp);
|
|
ASSERT (IRP_MJ_PNP == irpStack->MajorFunction);
|
|
|
|
commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
|
|
|
|
if (commonData->IsFDO) {
|
|
DrDebug(PNP_INFO, ("ntapm PNP: Functional DO: %x IRP: %x\n", DeviceObject, Irp));
|
|
|
|
status = NtApm_FDO_PnP (
|
|
DeviceObject,
|
|
Irp,
|
|
irpStack,
|
|
(PFDO_DEVICE_DATA) commonData);
|
|
} else {
|
|
DrDebug(PNP_INFO, ("ntapm: PNP: Physical DO: %x IRP: %x\n", DeviceObject, Irp));
|
|
|
|
status = NtApm_PDO_PnP (
|
|
DeviceObject,
|
|
Irp,
|
|
irpStack,
|
|
(PPDO_DEVICE_DATA) commonData);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NtApm_FDO_PnP (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpStack,
|
|
IN PFDO_DEVICE_DATA DeviceData
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Handle requests from the PlugPlay system for the BUS itself
|
|
|
|
NB: the various Minor functions of the PlugPlay system will not be
|
|
overlapped and do not have to be reentrant
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
KIRQL irql;
|
|
KEVENT event;
|
|
ULONG length;
|
|
ULONG i;
|
|
PLIST_ENTRY entry;
|
|
PPDO_DEVICE_DATA pdoData;
|
|
PDEVICE_RELATIONS relations;
|
|
PIO_STACK_LOCATION stack;
|
|
ULONG battresult;
|
|
|
|
PAGED_CODE ();
|
|
|
|
stack = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
switch (IrpStack->MinorFunction) {
|
|
case IRP_MN_START_DEVICE:
|
|
//
|
|
// BEFORE you are allowed to ``touch'' the device object to which
|
|
// the FDO is attached (that send an irp from the bus to the Device
|
|
// object to which the bus is attached). You must first pass down
|
|
// the start IRP. It might not be powered on, or able to access or
|
|
// something.
|
|
//
|
|
|
|
|
|
DrDebug(PNP_INFO, ("ntapm: Start Device\n"));
|
|
|
|
KeInitializeEvent (&event, NotificationEvent, FALSE);
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
|
|
IoSetCompletionRoutine (Irp,
|
|
NtApm_FDO_PnPComplete,
|
|
&event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
status = IoCallDriver (DeviceData->TopOfStack, Irp);
|
|
|
|
if (STATUS_PENDING == status) {
|
|
// wait for it...
|
|
|
|
status = KeWaitForSingleObject (&event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE, // Not allertable
|
|
NULL); // No timeout structure
|
|
|
|
ASSERT (STATUS_SUCCESS == status);
|
|
|
|
status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
//
|
|
// We must now complete the IRP, since we stopped it in the
|
|
// completetion routine with MORE_PROCESSING_REQUIRED.
|
|
//
|
|
break;
|
|
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
|
|
if (IrpStack->Parameters.QueryDeviceRelations.Type != BusRelations) {
|
|
//
|
|
// We don't support this
|
|
//
|
|
goto NtApm_FDO_PNP_DEFAULT;
|
|
}
|
|
|
|
//
|
|
// In theory, APM should be fired up by now.
|
|
// So call off into it to see if there is any sign
|
|
// of a battery on the box. If there is NOT, don't
|
|
// export the PDOs for the battery objects
|
|
//
|
|
battresult = DoApmReportBatteryStatus();
|
|
if (battresult & NTAPM_NO_SYS_BATT) {
|
|
//
|
|
// it appears that the machine does not have
|
|
// a battery. so don't export battery driver PDOs.
|
|
//
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver(DeviceData->TopOfStack, Irp);
|
|
}
|
|
|
|
DrDebug(PNP_INFO, ("ntapm: Query Relations "));
|
|
|
|
//
|
|
// create PDO for apm battery
|
|
//
|
|
if (NtApm_ApmBatteryPdo == NULL) {
|
|
status = NtApm_CreatePdo(
|
|
DeviceData,
|
|
NTAPM_PDO_NAME_APM_BATTERY,
|
|
&NtApm_ApmBatteryPdo
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto NtApm_DONE;
|
|
}
|
|
}
|
|
|
|
NtApm_InitializePdo(NtApm_ApmBatteryPdo, DeviceData, NTAPM_ID_APM_BATTERY);
|
|
|
|
//
|
|
// Tell PNP about our two child PDOs.
|
|
//
|
|
i = (Irp->IoStatus.Information == 0) ? 0 :
|
|
((PDEVICE_RELATIONS) Irp->IoStatus.Information)->Count;
|
|
|
|
//
|
|
// above should be count of PDOs
|
|
// make a new structure and our PDO to the end
|
|
//
|
|
|
|
//
|
|
// Need to allocate a new relations structure and add our
|
|
// PDOs to it.
|
|
//
|
|
length = sizeof(DEVICE_RELATIONS) + ((i + 1) * sizeof (PDEVICE_OBJECT));
|
|
|
|
relations = (PDEVICE_RELATIONS) ExAllocatePool (NonPagedPool, length);
|
|
|
|
if (relations == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto NtApm_DONE;
|
|
}
|
|
|
|
//
|
|
// Copy in the device objects so far
|
|
//
|
|
if (i) {
|
|
RtlCopyMemory (
|
|
relations->Objects,
|
|
((PDEVICE_RELATIONS) Irp->IoStatus.Information)->Objects,
|
|
i * sizeof (PDEVICE_OBJECT));
|
|
}
|
|
relations->Count = i + 1;
|
|
|
|
//
|
|
// add the apm battery PDO to the list
|
|
//
|
|
ObReferenceObject(NtApm_ApmBatteryPdo);
|
|
relations->Objects[i] = NtApm_ApmBatteryPdo;
|
|
|
|
//
|
|
// Replace the relations structure in the IRP with the new
|
|
// one.
|
|
//
|
|
if (Irp->IoStatus.Information != 0) {
|
|
ExFreePool ((PVOID) Irp->IoStatus.Information);
|
|
}
|
|
Irp->IoStatus.Information = (ULONG) relations;
|
|
|
|
//
|
|
// Set up and pass the IRP further down the stack
|
|
//
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
status = IoCallDriver (DeviceData->TopOfStack, Irp);
|
|
|
|
return status;
|
|
break;
|
|
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
case IRP_MN_STOP_DEVICE:
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|
Irp->IoStatus.Status = STATUS_SUCCESS; // we're lying, it's more like noop
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver (DeviceData->TopOfStack, Irp);
|
|
break;
|
|
|
|
NtApm_FDO_PNP_DEFAULT:
|
|
default:
|
|
//
|
|
// In the default case we merely call the next driver since
|
|
// we don't know what to do.
|
|
//
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
return IoCallDriver (DeviceData->TopOfStack, Irp);
|
|
}
|
|
|
|
NtApm_DONE:
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NtApm_FDO_PnPComplete (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
A completion routine for use when calling the lower device objects to
|
|
which our bus (FDO) is attached.
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER (DeviceObject);
|
|
UNREFERENCED_PARAMETER (Irp);
|
|
|
|
KeSetEvent ((PKEVENT) Context, 1, FALSE);
|
|
// No special priority
|
|
// No Wait
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED; // Keep this IRP
|
|
}
|
|
|
|
NTSTATUS
|
|
NtApm_PDO_PnP (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpStack,
|
|
IN PPDO_DEVICE_DATA DeviceData
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Handle requests from the PlugPlay system for the devices on the BUS
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_CAPABILITIES deviceCapabilities;
|
|
ULONG information;
|
|
PWCHAR buffer, buffer2;
|
|
ULONG length, length2, i, j;
|
|
NTSTATUS status;
|
|
KIRQL oldIrq;
|
|
PDEVICE_RELATIONS relations;
|
|
|
|
PAGED_CODE ();
|
|
|
|
status = Irp->IoStatus.Status;
|
|
|
|
//
|
|
// NB: since we are a bus enumerator, we have no one to whom we could
|
|
// defer these irps. Therefore we do not pass them down but merely
|
|
// return them.
|
|
//
|
|
|
|
switch (IrpStack->MinorFunction) {
|
|
case IRP_MN_QUERY_CAPABILITIES:
|
|
|
|
DrDebug(PNP_INFO, ("ntapm: Query Caps \n"));
|
|
|
|
//
|
|
// Get the packet.
|
|
//
|
|
deviceCapabilities = IrpStack->Parameters.DeviceCapabilities.Capabilities;
|
|
|
|
deviceCapabilities->UniqueID = FALSE;
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_QUERY_ID:
|
|
// Query the IDs of the device
|
|
DrDebug(PNP_INFO, ("ntapm: QueryID: 0x%x\n", IrpStack->Parameters.QueryId.IdType));
|
|
|
|
switch (IrpStack->Parameters.QueryId.IdType) {
|
|
|
|
case BusQueryDeviceID:
|
|
// this can be the same as the hardware ids (which requires a multi
|
|
// sz) ... we are just allocating more than enough memory
|
|
case BusQueryHardwareIDs:
|
|
// return a multi WCHAR (null terminated) string (null terminated)
|
|
// array for use in matching hardare ids in inf files;
|
|
//
|
|
|
|
buffer = DeviceData->HardwareIDs;
|
|
|
|
while (*(buffer++)) {
|
|
while (*(buffer++)) {
|
|
;
|
|
}
|
|
}
|
|
length = (buffer - DeviceData->HardwareIDs) * sizeof (WCHAR);
|
|
|
|
buffer = ExAllocatePool (PagedPool, length);
|
|
if (buffer) {
|
|
RtlCopyMemory (buffer, DeviceData->HardwareIDs, length);
|
|
Irp->IoStatus.Information = (ULONG) buffer;
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
break;
|
|
|
|
case BusQueryInstanceID:
|
|
//
|
|
// Build an instance ID. This is what PnP uses to tell if it has
|
|
// seen this thing before or not.
|
|
//
|
|
//
|
|
// return 0000 for all devices and have the flag set to not unique
|
|
//
|
|
length = APM_INSTANCE_IDS_LENGTH * sizeof(WCHAR);
|
|
buffer = ExAllocatePool(PagedPool, length);
|
|
|
|
if (buffer != NULL) {
|
|
RtlCopyMemory(buffer, APM_INSTANCE_IDS, length);
|
|
Irp->IoStatus.Information = (ULONG_PTR)buffer;
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
break;
|
|
|
|
case BusQueryCompatibleIDs:
|
|
// The generic ids for installation of this pdo.
|
|
break;
|
|
|
|
}
|
|
break;
|
|
|
|
case IRP_MN_START_DEVICE:
|
|
DrDebug(PNP_INFO, ("ntapm: Start Device \n"));
|
|
// Here we do what ever initialization and ``turning on'' that is
|
|
// required to allow others to access this device.
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_STOP_DEVICE:
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
DrDebug(PNP_INFO, ("ntapm: remove, stop, or Q remove or Q stop\n"));
|
|
//
|
|
// disallow Stop or Remove, since we don't want to test
|
|
// disengagement from APM if we don't have to
|
|
//
|
|
status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
|
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
DrDebug(PNP_INFO, ("ntapm: Cancel Stop Device or Cancel Remove \n"));
|
|
status = STATUS_SUCCESS; // more like "noop" than success
|
|
break;
|
|
|
|
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
|
|
break;
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
|
|
if (IrpStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) {
|
|
|
|
//
|
|
// Somebody else can handle this.
|
|
//
|
|
break;
|
|
}
|
|
|
|
ASSERT(((PULONG_PTR)Irp->IoStatus.Information) == NULL);
|
|
|
|
relations = (PDEVICE_RELATIONS) ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
|
|
|
|
if (relations == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else {
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR) relations;
|
|
relations->Count = 1;
|
|
relations->Objects[0] = DeviceObject;
|
|
ObReferenceObject(DeviceObject);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
case IRP_MN_READ_CONFIG:
|
|
case IRP_MN_WRITE_CONFIG: // we have no config space
|
|
case IRP_MN_EJECT:
|
|
case IRP_MN_SET_LOCK:
|
|
case IRP_MN_QUERY_INTERFACE: // We do not have any non IRP based interfaces.
|
|
default:
|
|
DrDebug(PNP_INFO, ("ntapm: PNP Not handled 0x%x\n", IrpStack->MinorFunction));
|
|
// this is a leaf node
|
|
// status = STATUS_NOT_IMPLEMENTED
|
|
// For PnP requests to the PDO that we do not understand we should
|
|
// return the IRP WITHOUT setting the status or information fields.
|
|
// They may have already been set by a filter (eg acpi).
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NtApm_CreatePdo (
|
|
PFDO_DEVICE_DATA FdoData,
|
|
PWCHAR PdoName,
|
|
PDEVICE_OBJECT * PDO
|
|
)
|
|
{
|
|
UNICODE_STRING pdoUniName;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE ();
|
|
//DbgBreakPoint();
|
|
|
|
//
|
|
// Create the PDOs
|
|
//
|
|
RtlInitUnicodeString (&pdoUniName, PdoName);
|
|
DrDebug(PNP_INFO, ("ntapm: CreatePdo: PDO Name: %ws\n", PdoName));
|
|
|
|
status = IoCreateDevice(
|
|
FdoData->Self->DriverObject,
|
|
sizeof (PDO_DEVICE_DATA),
|
|
&pdoUniName,
|
|
FILE_DEVICE_BUS_EXTENDER,
|
|
0,
|
|
FALSE,
|
|
PDO
|
|
);
|
|
DrDebug(PNP_L2, ("ntapm: CreatePdo: status = %08lx\n", status));
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
*PDO = NULL;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
NtApm_InitializePdo(
|
|
PDEVICE_OBJECT Pdo,
|
|
PFDO_DEVICE_DATA FdoData,
|
|
PWCHAR Id
|
|
)
|
|
{
|
|
PPDO_DEVICE_DATA pdoData;
|
|
|
|
PAGED_CODE ();
|
|
|
|
pdoData = (PPDO_DEVICE_DATA) Pdo->DeviceExtension;
|
|
|
|
DrDebug(PNP_INFO, ("ntapm: pdo 0x%x, extension 0x%x\n", Pdo, pdoData));
|
|
|
|
//
|
|
// Initialize the rest
|
|
//
|
|
pdoData->IsFDO = FALSE;
|
|
pdoData->Self = Pdo;
|
|
|
|
pdoData->ParentFdo = FdoData->Self;
|
|
|
|
pdoData->HardwareIDs = Id;
|
|
|
|
pdoData->UniqueID = 1;
|
|
|
|
Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
Pdo->Flags |= DO_POWER_PAGABLE;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
NtApm_Power (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
We do nothing special for power;
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION irpStack;
|
|
NTSTATUS status;
|
|
PCOMMON_DEVICE_DATA commonData;
|
|
|
|
PAGED_CODE ();
|
|
|
|
status = STATUS_SUCCESS;
|
|
irpStack = IoGetCurrentIrpStackLocation (Irp);
|
|
ASSERT (IRP_MJ_POWER == irpStack->MajorFunction);
|
|
|
|
commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
|
|
|
|
if (commonData->IsFDO) {
|
|
status = NtApm_FDO_Power ((PFDO_DEVICE_DATA) DeviceObject->DeviceExtension,Irp);
|
|
} else {
|
|
status = NtApm_PDO_Power ((PPDO_DEVICE_DATA) DeviceObject->DeviceExtension,Irp);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NtApm_FDO_Power (
|
|
PFDO_DEVICE_DATA Data,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION stack;
|
|
|
|
PAGED_CODE ();
|
|
|
|
PoStartNextPowerIrp(Irp);
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return PoCallDriver(Data->TopOfStack, Irp);
|
|
}
|
|
|
|
NTSTATUS
|
|
NtApm_PDO_Power (
|
|
PPDO_DEVICE_DATA PdoData,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION stack;
|
|
|
|
stack = IoGetCurrentIrpStackLocation (Irp);
|
|
switch (stack->MinorFunction) {
|
|
case IRP_MN_SET_POWER:
|
|
if ((stack->Parameters.Power.Type == SystemPowerState) &&
|
|
(stack->Parameters.Power.State.SystemState == PowerSystemWorking))
|
|
{
|
|
//
|
|
// system has just returned to the working state
|
|
// assert the user is present (they must be for the APM case)
|
|
// so that the display will light up, idle timers behave, etc.
|
|
//
|
|
PoSetSystemState(ES_USER_PRESENT);
|
|
}
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_QUERY_POWER:
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_WAIT_WAKE:
|
|
case IRP_MN_POWER_SEQUENCE:
|
|
default:
|
|
status = Irp->IoStatus.Status;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
PoStartNextPowerIrp(Irp);
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
|