1213 lines
29 KiB
C
1213 lines
29 KiB
C
/*++
|
||
|
||
Copyright (c) 1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
dispatch.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the dispatch code for the ACPI driver, NT version
|
||
|
||
Author:
|
||
|
||
Stephane Plante (splante)
|
||
|
||
Environment:
|
||
|
||
NT Kernel Model Driver only
|
||
|
||
Revision History:
|
||
|
||
Eric F. Nelson (enelson) October, '98 - Add GUID_ACPI_REGS_INTERFACE_...
|
||
|
||
--*/
|
||
|
||
#include "pch.h"
|
||
|
||
|
||
extern KEVENT ACPITerminateEvent;
|
||
extern PETHREAD ACPIThread;
|
||
|
||
//
|
||
// Local procedure to query HAL for ACPI register access routines
|
||
//
|
||
NTSTATUS
|
||
ACPIGetRegisterInterfaces(
|
||
IN PDEVICE_OBJECT PciPdo
|
||
);
|
||
|
||
//
|
||
// Local procedure to query HAL for port range rountines.
|
||
//
|
||
NTSTATUS
|
||
ACPIGetPortRangeInterfaces(
|
||
IN PDEVICE_OBJECT Pdo
|
||
);
|
||
|
||
|
||
NTSTATUS
|
||
ACPIDispatchAddDevice(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT PhysicalDeviceObject
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function contains code that is remarkably similar to the ACPIBuildNewXXX
|
||
routines. However there are certain core differences (and thus why this routine
|
||
is not named ACPIBuildNewFDO). The first difference is that at this time we do
|
||
not yet know the address of the ACPI _SB object. The second is that none of the
|
||
names need to be generated.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Represents this device driver
|
||
PhysicalDeviceObject- This is 1/2 of the Win9X dev node
|
||
|
||
Return Value:
|
||
|
||
Are we successfull or what?
|
||
|
||
--*/
|
||
{
|
||
KIRQL oldIrql;
|
||
NTSTATUS status;
|
||
PACPI_POWER_INFO powerInfo;
|
||
PDEVICE_EXTENSION deviceExtension = NULL;
|
||
PDEVICE_OBJECT newDeviceObject = NULL;
|
||
PDEVICE_OBJECT tempDeviceObject = NULL;
|
||
PUCHAR buffer = NULL;
|
||
PUCHAR deviceID = NULL;
|
||
PUCHAR instanceID = NULL;
|
||
|
||
//
|
||
// Note: This code isn't actually pagable --- it must be called
|
||
// PASSIVE_LEVEL
|
||
//
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Generate a Device ID (fake)
|
||
//
|
||
deviceID = ExAllocatePoolWithTag( NonPagedPool, 14, ACPI_STRING_POOLTAG);
|
||
if (deviceID == NULL) {
|
||
|
||
ACPIPrint( (
|
||
ACPI_PRINT_FAILURE,
|
||
"ACPIDispatchAddDevice: Could not allocate %#08lx bytes\n",
|
||
14
|
||
) );
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto ACPIDispatchAddDeviceExit;
|
||
|
||
}
|
||
strcpy( deviceID, "ACPI\\PNP0C08" );
|
||
|
||
//
|
||
// Generate an Instance ID (Fake)
|
||
//
|
||
instanceID = ExAllocatePoolWithTag( NonPagedPool, 11, ACPI_STRING_POOLTAG);
|
||
if (instanceID == NULL) {
|
||
|
||
ACPIPrint( (
|
||
ACPI_PRINT_FAILURE,
|
||
"ACPIDispatchAddDevice: Could not allocate %#08lx bytes\n",
|
||
11
|
||
) );
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto ACPIDispatchAddDeviceExit;
|
||
|
||
}
|
||
strcpy( instanceID, "0x5F534750" );
|
||
|
||
//
|
||
// Create a new object for the device
|
||
//
|
||
status = IoCreateDevice(
|
||
DriverObject,
|
||
0,
|
||
NULL,
|
||
FILE_DEVICE_ACPI,
|
||
0,
|
||
FALSE,
|
||
&newDeviceObject
|
||
);
|
||
|
||
//
|
||
// Did we make the device object?
|
||
//
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Let the world know we failed
|
||
//
|
||
ACPIPrint( (
|
||
ACPI_PRINT_FAILURE,
|
||
"ACPIDispatchAddDevice: %s - %#08lx\n",
|
||
deviceID, status
|
||
) );
|
||
goto ACPIDispatchAddDeviceExit;
|
||
|
||
}
|
||
|
||
//
|
||
// Attempt to attach to the PDO
|
||
//
|
||
tempDeviceObject = IoAttachDeviceToDeviceStack(
|
||
newDeviceObject,
|
||
PhysicalDeviceObject
|
||
);
|
||
if (tempDeviceObject == NULL) {
|
||
|
||
//
|
||
// An error occured while referencing the device...
|
||
//
|
||
ACPIPrint( (
|
||
ACPI_PRINT_CRITICAL,
|
||
"ACPIDispatchAddDevice: IoAttachDeviceToDeviceStack(%#08lx,%#08lx) "
|
||
"== NULL\n",
|
||
newDeviceObject, PhysicalDeviceObject
|
||
) );
|
||
|
||
//
|
||
// No such device
|
||
//
|
||
status = STATUS_NO_SUCH_DEVICE;
|
||
goto ACPIDispatchAddDeviceExit;
|
||
|
||
}
|
||
|
||
//
|
||
// At this point, we can attempt to create the device extension.
|
||
//
|
||
deviceExtension = ExAllocateFromNPagedLookasideList(
|
||
&DeviceExtensionLookAsideList
|
||
);
|
||
if (deviceExtension == NULL) {
|
||
|
||
ACPIPrint( (
|
||
ACPI_PRINT_CRITICAL,
|
||
"ACPIDispatchAddDevice: Could not allocate memory for extension\n"
|
||
) );
|
||
|
||
//
|
||
// Memory failure
|
||
//
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto ACPIDispatchAddDeviceExit;
|
||
|
||
}
|
||
|
||
//
|
||
// First, lets begin with a clean extension
|
||
//
|
||
RtlZeroMemory( deviceExtension, sizeof(DEVICE_EXTENSION) );
|
||
|
||
//
|
||
// Initialize the reference count mechanism.
|
||
//
|
||
InterlockedIncrement( &(deviceExtension->ReferenceCount) );
|
||
InterlockedIncrement( &(deviceExtension->OutstandingIrpCount) );
|
||
|
||
//
|
||
// Initialize the link fields
|
||
//
|
||
newDeviceObject->DeviceExtension = deviceExtension;
|
||
deviceExtension->DeviceObject = newDeviceObject;
|
||
deviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
|
||
deviceExtension->TargetDeviceObject = tempDeviceObject;
|
||
|
||
//
|
||
// Initialize the data fields
|
||
//
|
||
deviceExtension->Signature = ACPI_SIGNATURE;
|
||
deviceExtension->DispatchTable = &AcpiFdoIrpDispatch;
|
||
deviceExtension->DeviceID = deviceID;
|
||
deviceExtension->InstanceID = instanceID;
|
||
|
||
//
|
||
// Initialize the power info
|
||
//
|
||
powerInfo = &(deviceExtension->PowerInfo);
|
||
powerInfo->DevicePowerMatrix[PowerSystemUnspecified] =
|
||
PowerDeviceUnspecified;
|
||
powerInfo->DevicePowerMatrix[PowerSystemWorking] = PowerDeviceD0;
|
||
powerInfo->DevicePowerMatrix[PowerSystemSleeping1] = PowerDeviceD0;
|
||
powerInfo->DevicePowerMatrix[PowerSystemSleeping2] = PowerDeviceD0;
|
||
powerInfo->DevicePowerMatrix[PowerSystemSleeping3] = PowerDeviceD0;
|
||
powerInfo->DevicePowerMatrix[PowerSystemHibernate] = PowerDeviceD3;
|
||
powerInfo->DevicePowerMatrix[PowerSystemShutdown] = PowerDeviceD3;
|
||
powerInfo->SystemWakeLevel = PowerSystemUnspecified;
|
||
powerInfo->DeviceWakeLevel = PowerDeviceUnspecified;
|
||
|
||
//
|
||
// Initialize the flags
|
||
//
|
||
ACPIInternalUpdateFlags(
|
||
&(deviceExtension->Flags),
|
||
DEV_TYPE_FDO | DEV_CAP_NO_STOP | DEV_PROP_UID | DEV_PROP_HID |
|
||
DEV_PROP_FIXED_HID | DEV_PROP_FIXED_UID,
|
||
FALSE
|
||
);
|
||
|
||
//
|
||
// Initialize the list entry fields
|
||
//
|
||
InitializeListHead( &(deviceExtension->ChildDeviceList) );
|
||
InitializeListHead( &(deviceExtension->SiblingDeviceList) );
|
||
InitializeListHead( &(deviceExtension->EjectDeviceHead) );
|
||
InitializeListHead( &(deviceExtension->EjectDeviceList) );
|
||
|
||
//
|
||
// Initialize the queue for power requests
|
||
//
|
||
InitializeListHead( &(deviceExtension->PowerInfo.PowerRequestListEntry) );
|
||
|
||
//
|
||
// Yes! Now, setup the root device extension. We need a spinlock for this
|
||
//
|
||
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
|
||
RootDeviceExtension = deviceExtension;
|
||
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
|
||
|
||
//
|
||
// Query for ACPI register interfaces
|
||
//
|
||
ACPIGetRegisterInterfaces(PhysicalDeviceObject);
|
||
|
||
//
|
||
// Query for HAL port range interfaces.
|
||
//
|
||
ACPIGetPortRangeInterfaces(PhysicalDeviceObject);
|
||
|
||
#ifdef WMI_TRACING
|
||
//
|
||
// Initialize WMI Loging.
|
||
//
|
||
ACPIWmiInitLog(newDeviceObject);
|
||
//
|
||
// Enable WMI Logging for boot.
|
||
//
|
||
ACPIGetWmiLogGlobalHandle();
|
||
|
||
#endif //WMI_TRACING
|
||
|
||
//
|
||
// Clear the Initialization Flag
|
||
//
|
||
newDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
||
|
||
|
||
ACPIDispatchAddDeviceExit:
|
||
|
||
//
|
||
// Free things if the status is not success
|
||
//
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
if (deviceID != NULL) {
|
||
|
||
ExFreePool( deviceID );
|
||
|
||
}
|
||
|
||
if (instanceID != NULL) {
|
||
|
||
ExFreePool( instanceID );
|
||
|
||
}
|
||
|
||
if (tempDeviceObject != NULL) {
|
||
|
||
IoDetachDevice( tempDeviceObject );
|
||
|
||
}
|
||
|
||
if (newDeviceObject != NULL) {
|
||
|
||
IoDeleteDevice( newDeviceObject );
|
||
|
||
}
|
||
|
||
if (deviceExtension != NULL) {
|
||
|
||
ExFreeToNPagedLookasideList(
|
||
&DeviceExtensionLookAsideList,
|
||
deviceExtension
|
||
);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Done
|
||
//
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_LOADING,
|
||
deviceExtension,
|
||
"ACPIDispatchAddDevice: %08lx\n",
|
||
status
|
||
) );
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDispatchForwardIrp(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when the driver doesn't want to handle the
|
||
irp explicitly, but rather pass it along
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The target for the request
|
||
Irp - The request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
NTSTATUS status;
|
||
|
||
deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
||
if (deviceExtension->TargetDeviceObject) {
|
||
|
||
//
|
||
// Forward to target device
|
||
//
|
||
IoSkipCurrentIrpStackLocation (Irp);
|
||
status = IoCallDriver (deviceExtension->TargetDeviceObject, Irp);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Don't touch the IRP
|
||
//
|
||
#if DBG
|
||
UCHAR majorFunction;
|
||
|
||
majorFunction = IoGetCurrentIrpStackLocation(Irp)->MajorFunction;
|
||
|
||
ASSERT((majorFunction == IRP_MJ_PNP) ||
|
||
(majorFunction == IRP_MJ_DEVICE_CONTROL) ||
|
||
(majorFunction == IRP_MJ_SYSTEM_CONTROL));
|
||
#endif
|
||
|
||
status = Irp->IoStatus.Status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDispatchForwardOrFailPowerIrp(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when the driver doesn't want to handle the Power
|
||
Irp any longer
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The target of the power request
|
||
Irp - The power Request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
|
||
PoStartNextPowerIrp( Irp );
|
||
deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
||
|
||
//
|
||
// Forward the irp along, *unless* we are a PDO. In the later case,
|
||
// the irp is at the bottom of its stack (even if there is a target
|
||
// device object)
|
||
//
|
||
if ( !(deviceExtension->Flags & DEV_TYPE_PDO) &&
|
||
deviceExtension->TargetDeviceObject ) {
|
||
|
||
//
|
||
// Forward power irp to target device
|
||
//
|
||
IoCopyCurrentIrpStackLocationToNext ( Irp );
|
||
status = PoCallDriver (deviceExtension->TargetDeviceObject, Irp);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Complate/fail the irp with the not implemented code
|
||
//
|
||
status = Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDispatchForwardPowerIrp(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when the driver doesn't want to handle the Power
|
||
Irp any longer.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The target of the power request
|
||
Irp - The power Request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
|
||
PoStartNextPowerIrp( Irp );
|
||
deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
||
|
||
//
|
||
// Forward the irp along, *unless* we are a PDO. In the later case,
|
||
// the irp is at the bottom of its stack (even if there is a target
|
||
// device object)
|
||
//
|
||
if (deviceExtension->TargetDeviceObject &&
|
||
!(deviceExtension->Flags & DEV_TYPE_PDO)
|
||
) {
|
||
|
||
//
|
||
// Forward power irp to target device
|
||
//
|
||
IoSkipCurrentIrpStackLocation( Irp );
|
||
status = PoCallDriver (deviceExtension->TargetDeviceObject, Irp);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Complate/fail the irp with it's current status code
|
||
//
|
||
status = Irp->IoStatus.Status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDispatchPowerIrpUnhandled(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when an unhandled power IRP is received by an ACPI
|
||
enumerated PDO.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The target of the power request
|
||
Irp - The power Request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
|
||
#if DBG
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
|
||
deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
|
||
ASSERT(deviceExtension->Flags & DEV_TYPE_PDO);
|
||
#endif
|
||
|
||
PoStartNextPowerIrp( Irp );
|
||
|
||
//
|
||
// Complate/fail the irp with it's current status code
|
||
//
|
||
status = Irp->IoStatus.Status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDispatchIrp (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
{
|
||
KIRQL oldIrql;
|
||
LONG oldReferenceCount;
|
||
NTSTATUS status;
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
PIO_STACK_LOCATION irpSp;
|
||
PIRP_DISPATCH_TABLE dispatchTable;
|
||
PDRIVER_DISPATCH dispatch;
|
||
BOOLEAN remove;
|
||
KEVENT removeEvent;
|
||
UCHAR minorFunction;
|
||
|
||
|
||
//
|
||
// We need the IrpStack no matter what happens
|
||
//
|
||
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
|
||
//
|
||
// This is evil. But we have to do this is we are to remain in
|
||
// sync with the surprise removal code path. Note that we specifically
|
||
// do not call the ACPIInternalGetDeviceExtension() function here
|
||
// because that would ignore the surprise removed extension, which we
|
||
// want to know about here.
|
||
//
|
||
status = ACPIInternalGetDispatchTable(
|
||
DeviceObject,
|
||
&deviceExtension,
|
||
&dispatchTable
|
||
);
|
||
|
||
//
|
||
// We have the device extension. Now see if it exists. If it does not,
|
||
// then it is because we have deleted the object, but the system hasn't
|
||
// gotten around to destroying it
|
||
//
|
||
if (deviceExtension == NULL ||
|
||
deviceExtension->Flags & DEV_TYPE_REMOVED ||
|
||
deviceExtension->Signature != ACPI_SIGNATURE
|
||
) {
|
||
|
||
//
|
||
// Let the world know
|
||
//
|
||
ACPIPrint( (
|
||
ACPI_PRINT_WARNING,
|
||
"ACPIDispatchIrp: Deleted Device 0x%08lx got Irp 0x%08lx\n",
|
||
DeviceObject,
|
||
Irp
|
||
) );
|
||
|
||
//
|
||
// Is this a power irp?
|
||
//
|
||
if (irpSp->MajorFunction == IRP_MJ_POWER) {
|
||
|
||
return ACPIDispatchPowerIrpSurpriseRemoved( DeviceObject, Irp );
|
||
|
||
} else {
|
||
|
||
return ACPIDispatchIrpSurpriseRemoved( DeviceObject, Irp );
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Get the dispatch table that we will be using and the minor code as well,
|
||
// so that we can look it when required
|
||
//
|
||
minorFunction = irpSp->MinorFunction;
|
||
|
||
//
|
||
// Should be true because no IRPs should be received while we are removing
|
||
// ourselves. Anyone sending such an IRP missed a broadcast somewhere, and
|
||
// is thus in error.
|
||
//
|
||
ASSERT(deviceExtension->RemoveEvent == NULL) ;
|
||
|
||
//
|
||
// Handle the irp differently based on the major code that we are seeing
|
||
//
|
||
switch (irpSp->MajorFunction) {
|
||
case IRP_MJ_POWER:
|
||
|
||
if (minorFunction < (ACPIDispatchPowerTableSize-1) ) {
|
||
|
||
//
|
||
// Obtain the function pointer from the dispatch table
|
||
//
|
||
dispatch = dispatchTable->Power[ minorFunction ];
|
||
|
||
} else {
|
||
|
||
//
|
||
// Use the default dispatch point from the table
|
||
//
|
||
dispatch = dispatchTable->Power[ ACPIDispatchPowerTableSize -1 ];
|
||
|
||
}
|
||
|
||
//
|
||
// Reference the device
|
||
//
|
||
InterlockedIncrement(&deviceExtension->OutstandingIrpCount);
|
||
|
||
//
|
||
// Dispatch to handler, then remove our reference
|
||
//
|
||
status = dispatch (DeviceObject, Irp);
|
||
|
||
//
|
||
// Remove our reference, if the count goes to zero then signal
|
||
// for remove complete
|
||
//
|
||
ACPIInternalDecrementIrpReferenceCount( deviceExtension );
|
||
break;
|
||
|
||
case IRP_MJ_PNP:
|
||
|
||
if (minorFunction == IRP_MN_START_DEVICE) {
|
||
|
||
//
|
||
// Dispatch to start device handler
|
||
//
|
||
dispatch = dispatchTable->PnpStartDevice;
|
||
|
||
} else if (minorFunction < (ACPIDispatchPnpTableSize-1)) {
|
||
|
||
//
|
||
// Dispatch based on minor function. Not that we don't store
|
||
// IRP_MN_START_DEVICE (0x0) in this table, so we have to
|
||
// sub one from the minor code
|
||
//
|
||
dispatch = dispatchTable->Pnp[minorFunction];
|
||
|
||
} else {
|
||
|
||
//
|
||
// Out of dispatch tables range
|
||
//
|
||
dispatch = dispatchTable->Pnp[ACPIDispatchPnpTableSize-1];
|
||
|
||
}
|
||
|
||
//
|
||
// If this is a PnP remove device event, then perform special
|
||
// remove processing
|
||
//
|
||
if ((minorFunction == IRP_MN_REMOVE_DEVICE)||
|
||
(minorFunction == IRP_MN_SURPRISE_REMOVAL)) {
|
||
|
||
//
|
||
// Mark the device as removed (ie: block new irps from entering)
|
||
// and remember what the target event is
|
||
//
|
||
KeInitializeEvent (
|
||
&removeEvent,
|
||
SynchronizationEvent,
|
||
FALSE);
|
||
deviceExtension->RemoveEvent = &removeEvent;
|
||
|
||
//
|
||
// There may be some wake requests pending on this device. Lets
|
||
// cancel those irps now
|
||
//
|
||
ACPIWakeEmptyRequestQueue (deviceExtension );
|
||
|
||
//
|
||
// Are we the last irp to go through the device?
|
||
//
|
||
oldReferenceCount =
|
||
InterlockedDecrement(&deviceExtension->OutstandingIrpCount) ;
|
||
|
||
ASSERT(oldReferenceCount >= 0) ;
|
||
if ( oldReferenceCount != 0 ) {
|
||
|
||
//
|
||
// Wait for other irps to terminate
|
||
//
|
||
KeWaitForSingleObject (
|
||
&removeEvent,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
|
||
}
|
||
|
||
//
|
||
// Increment the outstanding IRP count. We do this because the
|
||
// device may not actually go away, in which case this needs to
|
||
// be at one after the IRP returns. Therefore the remove dispatch
|
||
// routine must not drop the IRP reference count of course...
|
||
//
|
||
InterlockedIncrement(&deviceExtension->OutstandingIrpCount);
|
||
|
||
//
|
||
// Dispatch to remove handler
|
||
//
|
||
deviceExtension->RemoveEvent = NULL;
|
||
status = dispatch (DeviceObject, Irp);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Increment the reference count on the device
|
||
//
|
||
InterlockedIncrement( &(deviceExtension->OutstandingIrpCount) );
|
||
|
||
//
|
||
// Dispatch to handler, then remove our reference
|
||
//
|
||
status = dispatch (DeviceObject, Irp);
|
||
|
||
//
|
||
// Decrement the reference count on the device
|
||
//
|
||
ACPIInternalDecrementIrpReferenceCount(
|
||
deviceExtension
|
||
);
|
||
|
||
}
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// These cases are similar
|
||
//
|
||
if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
|
||
|
||
dispatch = dispatchTable->DeviceControl;
|
||
|
||
} else if (irpSp->MajorFunction == IRP_MJ_CREATE ||
|
||
minorFunction == IRP_MJ_CLOSE) {
|
||
|
||
dispatch = dispatchTable->CreateClose;
|
||
|
||
} else if (irpSp->MajorFunction == IRP_MJ_SYSTEM_CONTROL) {
|
||
|
||
dispatch = dispatchTable->SystemControl;
|
||
|
||
} else {
|
||
|
||
dispatch = dispatchTable->Other;
|
||
}
|
||
|
||
//
|
||
// Reference the device
|
||
//
|
||
InterlockedIncrement(&deviceExtension->OutstandingIrpCount);
|
||
|
||
//
|
||
// Dispatch to handler
|
||
//
|
||
status = dispatch (DeviceObject, Irp);
|
||
|
||
//
|
||
// Remove our reference
|
||
//
|
||
ACPIInternalDecrementIrpReferenceCount( deviceExtension );
|
||
break;
|
||
|
||
}
|
||
|
||
//
|
||
// Done
|
||
//
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDispatchIrpInvalid (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
{
|
||
//
|
||
// Fail the Irp as something that we don't support
|
||
//
|
||
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDispatchIrpSuccess (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
{
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDispatchIrpSurpriseRemoved(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
{
|
||
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDispatchPowerIrpFailure(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
{
|
||
PoStartNextPowerIrp( Irp );
|
||
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDispatchPowerIrpInvalid (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
{
|
||
PoStartNextPowerIrp( Irp );
|
||
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDispatchPowerIrpSuccess (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
{
|
||
PoStartNextPowerIrp( Irp );
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIDispatchPowerIrpSurpriseRemoved (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
{
|
||
PoStartNextPowerIrp( Irp );
|
||
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE ;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
}
|
||
|
||
VOID
|
||
ACPIUnload(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when the driver is supposed to unload
|
||
|
||
Since this is a PnP driver, I'm not to sure what I need to do here.
|
||
Lets just assume that the system is responsible for sending me removes
|
||
for all my device objects, and I can just clean up the rest
|
||
|
||
Arguments:
|
||
|
||
DriverObject - The pointer to ourselves
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
--*/
|
||
{
|
||
UNREFERENCED_PARAMETER(DriverObject);
|
||
|
||
//
|
||
// Signal termination to the worker thread.
|
||
//
|
||
KeSetEvent(&ACPITerminateEvent, 0, FALSE);
|
||
|
||
//
|
||
// And wait for the worker thread to die.
|
||
//
|
||
KeWaitForSingleObject(ACPIThread, Executive, KernelMode, FALSE, 0);
|
||
|
||
ObDereferenceObject (ACPIThread);
|
||
|
||
//
|
||
// Make ourselves clean up
|
||
//
|
||
ACPICleanUp();
|
||
|
||
//
|
||
// Free Memory
|
||
//
|
||
ExDeleteNPagedLookasideList(&BuildRequestLookAsideList);
|
||
ExDeleteNPagedLookasideList(&RequestLookAsideList);
|
||
ExDeleteNPagedLookasideList(&DeviceExtensionLookAsideList);
|
||
ExDeleteNPagedLookasideList(&ObjectDataLookAsideList);
|
||
ExDeleteNPagedLookasideList(&PswContextLookAsideList);
|
||
if (AcpiRegistryPath.Buffer != NULL) {
|
||
|
||
ExFreePool( AcpiRegistryPath.Buffer );
|
||
|
||
}
|
||
if (AcpiProcessorString.Buffer != NULL) {
|
||
|
||
ExFreePool( AcpiProcessorString.Buffer );
|
||
|
||
}
|
||
|
||
//
|
||
// Done
|
||
//
|
||
ACPIPrint( (
|
||
ACPI_PRINT_WARNING,
|
||
"ACPIUnload: Called --- unloading ACPI driver\n"
|
||
) );
|
||
|
||
ASSERT( DriverObject->DeviceObject == NULL );
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
ACPIGetRegisterInterfaces(
|
||
IN PDEVICE_OBJECT PciPdo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function queries the PCI bus for interfaces used to access
|
||
the ACPI registers
|
||
|
||
Arguments:
|
||
|
||
PciPdo - PDO for the PCI bus
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PDEVICE_OBJECT topDeviceInStack;
|
||
KEVENT irpCompleted;
|
||
PIRP irp;
|
||
IO_STATUS_BLOCK statusBlock;
|
||
PIO_STACK_LOCATION irpStack;
|
||
|
||
extern PREAD_ACPI_REGISTER AcpiReadRegisterRoutine;
|
||
extern PWRITE_ACPI_REGISTER AcpiWriteRegisterRoutine;
|
||
|
||
ACPI_REGS_INTERFACE_STANDARD AcpiRegsInterfaceStd;
|
||
|
||
PAGED_CODE();
|
||
|
||
KeInitializeEvent(&irpCompleted, SynchronizationEvent, FALSE);
|
||
|
||
//
|
||
// Send an IRP to the PCI bus to get ACPI register interfaces.
|
||
//
|
||
topDeviceInStack = IoGetAttachedDeviceReference(PciPdo);
|
||
if (!topDeviceInStack) {
|
||
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
|
||
}
|
||
|
||
irp = IoBuildSynchronousFsdRequest(
|
||
IRP_MJ_PNP,
|
||
topDeviceInStack,
|
||
NULL, // Buffer
|
||
0, // Length
|
||
0, // StartingOffset
|
||
&irpCompleted,
|
||
&statusBlock
|
||
);
|
||
if (!irp) {
|
||
|
||
ObDereferenceObject( topDeviceInStack );
|
||
return STATUS_UNSUCCESSFUL;
|
||
|
||
}
|
||
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
||
irp->IoStatus.Information = 0;
|
||
irpStack = IoGetNextIrpStackLocation(irp);
|
||
|
||
//
|
||
// Set the function codes and parameters.
|
||
//
|
||
irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
||
irpStack->Parameters.QueryInterface.InterfaceType =
|
||
&GUID_ACPI_REGS_INTERFACE_STANDARD;
|
||
irpStack->Parameters.QueryInterface.Size =
|
||
sizeof(ACPI_REGS_INTERFACE_STANDARD);
|
||
irpStack->Parameters.QueryInterface.Version = 1;
|
||
irpStack->Parameters.QueryInterface.Interface =
|
||
(PINTERFACE)&AcpiRegsInterfaceStd;
|
||
irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
||
|
||
//
|
||
// Call the driver and wait for completion
|
||
//
|
||
status = IoCallDriver(topDeviceInStack, irp);
|
||
if (status == STATUS_PENDING) {
|
||
|
||
KeWaitForSingleObject(
|
||
&irpCompleted,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
status = statusBlock.Status;
|
||
|
||
}
|
||
|
||
//
|
||
// Done with object reference...
|
||
//
|
||
ObDereferenceObject( topDeviceInStack );
|
||
|
||
//
|
||
// Did we get some interfaces?
|
||
//
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
AcpiReadRegisterRoutine = AcpiRegsInterfaceStd.ReadAcpiRegister;
|
||
AcpiWriteRegisterRoutine = AcpiRegsInterfaceStd.WriteAcpiRegister;
|
||
|
||
}
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ACPIGetPortRangeInterfaces(
|
||
IN PDEVICE_OBJECT Pdo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function queries the HAL for interfaces used to manage
|
||
the port ranges registers
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status;
|
||
PDEVICE_OBJECT topDeviceInStack;
|
||
KEVENT irpCompleted;
|
||
PIRP irp;
|
||
IO_STATUS_BLOCK StatusBlock;
|
||
PIO_STACK_LOCATION irpStack;
|
||
|
||
PAGED_CODE();
|
||
|
||
KeInitializeEvent(&irpCompleted, SynchronizationEvent, FALSE);
|
||
|
||
//
|
||
// Send an IRP to the PCI bus to get ACPI register interfaces.
|
||
//
|
||
topDeviceInStack = IoGetAttachedDeviceReference(Pdo);
|
||
if (!topDeviceInStack) {
|
||
return STATUS_NO_SUCH_DEVICE;
|
||
}
|
||
|
||
irp = IoBuildSynchronousFsdRequest(
|
||
IRP_MJ_PNP,
|
||
topDeviceInStack,
|
||
NULL, // Buffer
|
||
0, // Length
|
||
0, // StartingOffset
|
||
&irpCompleted,
|
||
&StatusBlock
|
||
);
|
||
if (!irp) {
|
||
|
||
ObDereferenceObject( topDeviceInStack );
|
||
return STATUS_UNSUCCESSFUL;
|
||
|
||
}
|
||
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
||
irp->IoStatus.Information = 0;
|
||
irpStack = IoGetNextIrpStackLocation(irp);
|
||
|
||
//
|
||
// Set the function codes and parameters.
|
||
//
|
||
irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
||
irpStack->Parameters.QueryInterface.InterfaceType =
|
||
&GUID_ACPI_PORT_RANGES_INTERFACE_STANDARD;
|
||
irpStack->Parameters.QueryInterface.Size =
|
||
sizeof(HAL_PORT_RANGE_INTERFACE);
|
||
irpStack->Parameters.QueryInterface.Version = 0;
|
||
irpStack->Parameters.QueryInterface.Interface =
|
||
(PINTERFACE)&HalPortRangeInterface;
|
||
irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
||
|
||
//
|
||
// Call the driver and wait for completion
|
||
//
|
||
Status = IoCallDriver(topDeviceInStack, irp);
|
||
if (Status == STATUS_PENDING) {
|
||
|
||
KeWaitForSingleObject(
|
||
&irpCompleted,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
|
||
Status = StatusBlock.Status;
|
||
}
|
||
|
||
//
|
||
// Done with object reference...
|
||
//
|
||
ObDereferenceObject( topDeviceInStack );
|
||
|
||
//
|
||
// Did we get some interfaces?
|
||
//
|
||
if (NT_SUCCESS(Status)) {
|
||
// XXX
|
||
}
|
||
|
||
return Status;
|
||
}
|