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.
524 lines
12 KiB
524 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 2000-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
acpisim.c
|
|
|
|
Abstract:
|
|
|
|
ACPI BIOS Simulator / Generic 3rd Party Operation Region Provider
|
|
|
|
Author(s):
|
|
|
|
Vincent Geglia
|
|
Michael T. Murphy
|
|
Chris Burgess
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Notes:
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
//
|
|
// General includes
|
|
//
|
|
|
|
#include <ntddk.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <ntpoapi.h>
|
|
|
|
//
|
|
// Specific includes
|
|
//
|
|
|
|
#include "acpisim.h"
|
|
#include "dispatch.h"
|
|
#include "util.h"
|
|
|
|
//
|
|
// Debug global flag
|
|
//
|
|
#ifdef DBG
|
|
extern ULONG AcpisimDebugMask = 0x00000000;
|
|
#endif
|
|
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
PDRIVER_OBJECT_EXTENSION g_DriverObjectExtension = 0;
|
|
|
|
//
|
|
// Define supported IRPs, friendly name them, and associate handlers
|
|
//
|
|
|
|
IRP_DISPATCH_TABLE g_IrpDispatchTable [] = {
|
|
IRP_MJ_PNP, "PnP Irp", AcpisimDispatchPnp,
|
|
IRP_MJ_POWER, "Power Irp", AcpisimDispatchPower,
|
|
IRP_MJ_DEVICE_CONTROL, "IOCTL Irp", AcpisimDispatchIoctl,
|
|
IRP_MJ_CREATE, "Create Irp", AcpisimCreateClose,
|
|
IRP_MJ_CLOSE, "Close Irp", AcpisimCreateClose,
|
|
IRP_MJ_SYSTEM_CONTROL, "System Control IRP", AcpisimDispatchSystemControl
|
|
};
|
|
|
|
//
|
|
// Private funtion prototypes
|
|
//
|
|
|
|
NTSTATUS DriverEntry
|
|
(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
NTSTATUS
|
|
AcpisimGeneralDispatch
|
|
(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
AcpisimUnload
|
|
(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
NTSTATUS
|
|
AcpisimAddDevice
|
|
(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT Pdo
|
|
);
|
|
|
|
//
|
|
// Define pageable / init discardable routines
|
|
//
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text (INIT, DriverEntry)
|
|
#endif
|
|
|
|
|
|
NTSTATUS DriverEntry
|
|
(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Installable driver initialization entry point.
|
|
This entry point is called directly by the I/O system.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - pointer to the driver object
|
|
|
|
RegistryPath - pointer to a unicode string representing the path,
|
|
to driver-specific key in the registry.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful,
|
|
STATUS_UNSUCCESSFUL otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
ULONG count = 0, subcount = 0;
|
|
|
|
DBG_PRINT (DBG_INFO, "Entering DriverEntry\n");
|
|
|
|
status = IoAllocateDriverObjectExtension (DriverObject,
|
|
(PVOID) 'GLBL',
|
|
sizeof (DRIVER_OBJECT_EXTENSION),
|
|
&g_DriverObjectExtension);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
DBG_PRINT (DBG_ERROR, "Unable to allocate global driver object extension (%lx).\n", status);
|
|
goto EndDriverEntry;
|
|
}
|
|
|
|
RtlZeroMemory (g_DriverObjectExtension, sizeof (DRIVER_OBJECT_EXTENSION));
|
|
|
|
RtlInitUnicodeString (&g_DriverObjectExtension->RegistryPath,
|
|
(PCWSTR) RegistryPath->Buffer);
|
|
|
|
g_DriverObjectExtension->DriverObject = DriverObject;
|
|
|
|
//
|
|
// Init dispatch points. We'll use a generic dispatch routine for
|
|
// IRP types we handle.
|
|
//
|
|
|
|
while (count <= IRP_MJ_MAXIMUM_FUNCTION) {
|
|
|
|
for (subcount = 0; subcount < sizeof (g_IrpDispatchTable) / sizeof (IRP_DISPATCH_TABLE); subcount++) {
|
|
|
|
if (count == g_IrpDispatchTable[subcount].IrpFunction) {
|
|
DriverObject->MajorFunction [count] = AcpisimGeneralDispatch;
|
|
}
|
|
}
|
|
|
|
count ++;
|
|
}
|
|
|
|
DriverObject->DriverUnload = AcpisimUnload;
|
|
DriverObject->DriverExtension->AddDevice = AcpisimAddDevice;
|
|
|
|
|
|
EndDriverEntry:
|
|
|
|
DBG_PRINT (DBG_INFO, "Exiting DriverEntry\n");
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
AcpisimGeneralDispatch
|
|
(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a general dispatch routine for supported IRPs.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to the device object
|
|
|
|
Irp - pointer to the IRP being passed in
|
|
|
|
Return Value:
|
|
|
|
status of IRP handling
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject);
|
|
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (Irp);
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
ULONG count = 0;
|
|
|
|
DBG_PRINT (DBG_INFO, "Entering AcpisimGeneralDispatch\n");
|
|
|
|
|
|
InterlockedIncrement (&deviceextension->OutstandingIrpCount);
|
|
|
|
//
|
|
// Acquire the remove lock for outstanding I/O
|
|
//
|
|
|
|
IoAcquireRemoveLock (&deviceextension->RemoveLock, Irp);
|
|
|
|
while (count < sizeof (g_IrpDispatchTable) / sizeof (IRP_DISPATCH_TABLE)) {
|
|
|
|
if (irpsp->MajorFunction == g_IrpDispatchTable[count].IrpFunction) {
|
|
|
|
DBG_PRINT (DBG_INFO,
|
|
"Recognized IRP MajorFunction = 0x%x '%s'.\n",
|
|
g_IrpDispatchTable[count].IrpFunction,
|
|
g_IrpDispatchTable[count].IrpName
|
|
);
|
|
|
|
status = g_IrpDispatchTable[count].IrpHandler (DeviceObject, Irp);
|
|
|
|
goto EndAcpisimProcessIncomingIrp;
|
|
}
|
|
|
|
count ++;
|
|
}
|
|
|
|
//
|
|
// Unrecognized IRP - pass it on
|
|
//
|
|
|
|
DBG_PRINT (DBG_INFO, "Unrecognized IRP MajorFunction = 0x%x\n, pass it on.\n", irpsp->MajorFunction);
|
|
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
status = IoCallDriver (deviceextension->NextDevice, Irp);
|
|
|
|
EndAcpisimProcessIncomingIrp:
|
|
|
|
//
|
|
// If the status is pending, the IRP hasn't "left" our
|
|
// driver yet. Whoever completes the IRP will do the
|
|
// decrement.
|
|
//
|
|
|
|
if (status != STATUS_PENDING)
|
|
{
|
|
AcpisimDecrementIrpCount (DeviceObject);
|
|
IoReleaseRemoveLock (&deviceextension->RemoveLock, Irp);
|
|
}
|
|
|
|
DBG_PRINT (DBG_INFO, "Exiting AcpisimGeneralDispatch\n");
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
AcpisimUnload
|
|
(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the driver unload routine.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - pointer to the driver object
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
PDRIVER_OBJECT_EXTENSION driverobjectextension = 0;
|
|
|
|
driverobjectextension = IoGetDriverObjectExtension (DriverObject,
|
|
(PVOID) 'GLBL');
|
|
if (!driverobjectextension) {
|
|
DBG_PRINT (DBG_ERROR, "Unable to get driver object extension. Memory will probably leak.\n");
|
|
|
|
goto EndAcpisimUnload;
|
|
}
|
|
|
|
EndAcpisimUnload:
|
|
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
AcpisimAddDevice
|
|
(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT Pdo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the driver WDM AddDevice Routine
|
|
|
|
Arguments:
|
|
|
|
DriverObject - pointer to the driver object
|
|
Pdo - pointer to PDO for this device
|
|
|
|
Return Value:
|
|
|
|
status of device addition
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
PDEVICE_OBJECT deviceobject = 0;
|
|
PDEVICE_EXTENSION deviceextension = 0;
|
|
CONST GUID guid = ACPISIM_GUID;
|
|
|
|
|
|
DBG_PRINT (DBG_INFO, "Entering AcpisimAddDevice.\n");
|
|
|
|
//
|
|
// If Pdo is NULL, we are being asked to do legacy detection.
|
|
// Our device is never legacy detected, so return accordingly.
|
|
//
|
|
|
|
if (Pdo == NULL) {
|
|
|
|
DBG_PRINT (DBG_WARN, "AddDevice - asked to do legacy detection (Pdo = NULL). Not supported...\n");
|
|
status = STATUS_NO_MORE_ENTRIES;
|
|
goto EndAcpisimAddDevice;
|
|
}
|
|
|
|
//
|
|
// Create our FDO. Don't use a name - we'll use a device interface
|
|
//
|
|
|
|
status = IoCreateDevice (DriverObject,
|
|
sizeof (DEVICE_EXTENSION),
|
|
0,
|
|
FILE_DEVICE_UNKNOWN,
|
|
0,
|
|
TRUE,
|
|
&deviceobject);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
|
|
DBG_PRINT (DBG_ERROR, "Can't create FDO. Status = %lx.\n", status);
|
|
goto EndAcpisimAddDevice;
|
|
}
|
|
|
|
//
|
|
// Init our device extension
|
|
//
|
|
|
|
deviceextension = deviceobject->DeviceExtension;
|
|
RtlZeroMemory (deviceextension, sizeof (DEVICE_EXTENSION));
|
|
|
|
deviceextension->Signature = ACPISIM_TAG;
|
|
deviceextension->PnpState = PNP_STATE_INITIALIZING;
|
|
deviceextension->OutstandingIrpCount = 1;
|
|
deviceextension->DeviceObject = deviceobject;
|
|
deviceextension->Pdo = Pdo;
|
|
|
|
KeInitializeEvent (&deviceextension->IrpsCompleted, SynchronizationEvent, FALSE);
|
|
|
|
//
|
|
// Initialize the remove lock
|
|
//
|
|
|
|
IoInitializeRemoveLock (&deviceextension->RemoveLock,
|
|
ACPISIM_TAG,
|
|
1,
|
|
20);
|
|
|
|
//
|
|
// Attach our newly created FDO to the device stack
|
|
//
|
|
|
|
deviceextension->NextDevice = IoAttachDeviceToDeviceStack (deviceobject, Pdo);
|
|
|
|
if (!deviceextension->NextDevice) {
|
|
DBG_PRINT (DBG_ERROR, "Error attaching to device stack. AddDevice failed.\n");
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
goto EndAcpisimAddDevice;
|
|
}
|
|
|
|
//
|
|
// Set up device object flags
|
|
// Copy DO_POWER_PAGABLE and DO_POWER_INRUSH from next device to
|
|
// play by rules, and avoid bugcheck 0x9F.
|
|
//
|
|
|
|
deviceobject->Flags |= (deviceextension->NextDevice->Flags & DO_POWER_PAGABLE);
|
|
deviceobject->Flags |= (deviceextension->NextDevice->Flags & DO_POWER_INRUSH);
|
|
|
|
//
|
|
// Register our device interface, so we can be accessed from user mode
|
|
//
|
|
|
|
status = IoRegisterDeviceInterface (Pdo,
|
|
&guid,
|
|
NULL,
|
|
&deviceextension->InterfaceString);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
DBG_PRINT (DBG_ERROR, "Error registering device interface. Status = %lx.\n", status);
|
|
|
|
goto EndAcpisimAddDevice;
|
|
}
|
|
|
|
AcpisimSetDevExtFlags (deviceobject, DE_FLAG_INTERFACE_REGISTERED);
|
|
|
|
//
|
|
// In AddDevice, we cannot determine power state because
|
|
// we are not allowed to touch the hardware. Initialize
|
|
// it to PowerDeviceUnspecified.
|
|
//
|
|
|
|
AcpisimUpdatePowerState (deviceobject, POWER_STATE_WORKING);
|
|
AcpisimUpdateDevicePowerState (deviceobject, PowerDeviceUnspecified);
|
|
|
|
//
|
|
// We are done adding our device - clear DO_DEVICE_INITIALIZING
|
|
//
|
|
|
|
deviceobject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
|
|
EndAcpisimAddDevice:
|
|
|
|
//
|
|
// Do cleanup, if necessary
|
|
//
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
|
|
if (deviceobject) {
|
|
|
|
if (deviceextension && deviceextension->NextDevice) {
|
|
|
|
IoDetachDevice (deviceextension->NextDevice);
|
|
}
|
|
|
|
IoDeleteDevice (deviceobject);
|
|
}
|
|
}
|
|
|
|
DBG_PRINT (DBG_INFO, "Exiting AcpisimAddDevice (%lx).\n", status);
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
AcpisimDbgPrint
|
|
(
|
|
ULONG DebugLevel,
|
|
TCHAR *Text,
|
|
...
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints to the debugger if checked build, and the print level
|
|
is unmasked.
|
|
|
|
Arguments:
|
|
|
|
DebugLevel - print level to associate message with
|
|
|
|
Text - Message to print
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
TCHAR textout[2000];
|
|
|
|
va_list va;
|
|
va_start (va, Text);
|
|
vsprintf (textout, Text, va);
|
|
va_end (va);
|
|
|
|
#if DBG
|
|
|
|
if (DebugLevel & AcpisimDebugMask) {
|
|
DbgPrint ("ACPISIM:");
|
|
DbgPrint (textout);
|
|
}
|
|
#endif
|
|
|
|
}
|