windows-nt/Source/XPSP1/NT/base/busdrv/acpi/driver/nt/osnotify.c

1534 lines
33 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
osnotify.c
Abstract:
This module implements all the callbacks that are NT specific from
the AML Interpreter
Environment
Kernel mode only
Revision History:
01-Mar-98 Initial Revision [split from callback.c]
--*/
#include "pch.h"
//
// Make sure that we have permanent storage for our fatal error context
//
ACPI_FATAL_ERROR_CONTEXT AcpiFatalContext;
//
// Spinlock to protect the entire thing
KSPIN_LOCK AcpiFatalLock;
//
// Is there an outstanding Fatal Error Context?
//
BOOLEAN AcpiFatalOutstanding;
NTSTATUS
EXPORT
OSNotifyCreate(
IN ULONG ObjType,
IN PNSOBJ AcpiObject
)
/*++
Routine Description:
This routine is called whenever a new object is created by the interpreter
This routine dispatches based on what object type it is.
Arguments:
ObjType - What type of object it is
AcpiObject - Pointer to the new ACPI Object
Return Value:
NTSTATUS
--*/
{
KIRQL oldIrql;
NTSTATUS status = STATUS_SUCCESS;
ASSERT( AcpiObject != NULL );
//
// We will touch the device tree. So we need to hold the correct lock
//
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
switch(ObjType) {
case OBJTYPE_DEVICE:
status = OSNotifyCreateDevice( AcpiObject, 0 );
break;
case OBJTYPE_OPREGION:
status = OSNotifyCreateOperationRegion( AcpiObject );
break;
case OBJTYPE_POWERRES:
status = OSNotifyCreatePowerResource( AcpiObject );
break;
case OBJTYPE_PROCESSOR:
status = OSNotifyCreateProcessor( AcpiObject, 0 );
break;
case OBJTYPE_THERMALZONE:
status = OSNotifyCreateThermalZone( AcpiObject, 0 );
break;
default:
ACPIPrint( (
ACPI_PRINT_WARNING,
"OSNotifyCreate: received unhandled type %x\n",
ObjType
) );
status = STATUS_SUCCESS;
}
//
// Done with this lock
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
//
// What happened?
//
ACPIPrint( (
ACPI_PRINT_LOADING,
"OSNotifyCreate: %p (%s) = %08lx\n",
AcpiObject,
ACPIAmliNameObject( AcpiObject ),
status
) );
//
// Done --- Always succeed
//
return STATUS_SUCCESS;
}
NTSTATUS
OSNotifyCreateDevice(
IN PNSOBJ AcpiObject,
IN ULONGLONG OptionalFlags
)
/*++
Routine Description:
This routine is called whenever a new device appears. This routine is
callable at DispatchLevel.
Arguments:
AcpiObject - Pointer to new ACPI Object
OptionalFlags - Properties of the Device Extension that should be
set when its created.
Return Value:
NTSTATUS
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension = NULL;
PDEVICE_EXTENSION parentExtension;
PNSOBJ parentObject;
ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
ASSERT( AcpiObject != NULL);
//
// First, we need a pointer to the parent node
//
parentObject = AcpiObject->pnsParent;
ASSERT( parentObject != NULL );
//
// Grab the device extension associated with the parent. We need
// this information to help link the parent properly into the tree
//
parentExtension = (PDEVICE_EXTENSION) parentObject->Context;
if (parentExtension == NULL) {
//
// In this case, we can assume that the parent extension is the root
// device extension.
//
parentExtension = RootDeviceExtension;
}
ASSERT( parentExtension != NULL );
//
// Now build an extension for the node
//
status = ACPIBuildDeviceExtension(
AcpiObject,
parentExtension,
&deviceExtension
);
if (deviceExtension == NULL) {
status = STATUS_UNSUCCESSFUL;
}
if (NT_SUCCESS(status)) {
//
// Incremement the reference count on the node. We do this because
// we are going to be doing work (which will take a long time
// to complete, anyways), and we don't want to hold the lock for that
// entire time. If we incr the reference count, then we guarantee that
// no one can come along and kick the feet out from underneath us
//
InterlockedIncrement( &(deviceExtension->ReferenceCount) );
}
//
// What happend to the creation of the extension?
//
if (!NT_SUCCESS(status)) {
//
// We should have succeeded at whatever we are doing --- so this is
// a bad place to be
//
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSNotifyCreateDevice: NSObj %p Failed %08lx\n",
AcpiObject,
status
) );
goto OSNotifyCreateDeviceExit;
}
//
// Set the optional flags if there are any
//
ACPIInternalUpdateFlags(
&(deviceExtension->Flags),
OptionalFlags,
FALSE
);
//
// Make sure to queue the request
//
status = ACPIBuildDeviceRequest(
deviceExtension,
NULL,
NULL,
FALSE
);
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSNotifyCreateDevice: ACPIBuildDeviceRequest(%p) = %08lx\n",
deviceExtension,
status
) );
goto OSNotifyCreateDeviceExit;
}
OSNotifyCreateDeviceExit:
//
// There is some work that will be done later
//
return status;
}
NTSTATUS
OSNotifyCreateOperationRegion(
IN PNSOBJ AcpiObject
)
/*++
Routine Description:
This routine is called whenever a new operation region is created.
This routine is callable at DispatchLevel.
Arguments:
AcpiObject - Pointer to the new ACPI Operation Region Object
Return Value:
NTSTATUS
--*/
{
PDEVICE_EXTENSION parentExtension;
PNSOBJ parentObject;
POPREGIONOBJ opRegion;
//
// Sanity Check
//
ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
ASSERT( AcpiObject != NULL );
ASSERT( NSGETOBJTYPE(AcpiObject) == OBJTYPE_OPREGION );
ASSERT( AcpiObject->ObjData.pbDataBuff != NULL );
//
// Get the OpRegion Object from the namespace object
//
opRegion = (POPREGIONOBJ) AcpiObject->ObjData.pbDataBuff;
if (opRegion->bRegionSpace != REGSPACE_PCIBARTARGET) {
//
// This isn't a PCI Bar Target Operation Region, so there
// is nothing to do
//
return STATUS_SUCCESS;
}
//
// There are two cases to consider. The first case is the
// one where the Operation Region is "static" in nature and
// thus exists under some sort of device. The second case is
// the one where the Operation Region is "dynamic" in nature
// and thus exists under some sort of method. So, we want to
// look at parent objects until we hit one that isn't a method
// or is a device...
//
parentObject = AcpiObject->pnsParent;
while (parentObject != NULL) {
//
// If the parent object is a method, then look at its parent
//
if (NSGETOBJTYPE(parentObject) == OBJTYPE_METHOD) {
parentObject = parentObject->pnsParent;
continue;
}
//
// If the parent object isn't a device, then stop...
//
if (NSGETOBJTYPE(parentObject) != OBJTYPE_DEVICE) {
break;
}
//
// Grab the device extension (bad things happen if it doesn't
// already exist
//
parentExtension = (PDEVICE_EXTENSION) parentObject->Context;
if (parentExtension) {
ACPIInternalUpdateFlags(
&(parentExtension->Flags),
DEV_CAP_PCI_BAR_TARGET,
FALSE
);
}
break;
}
//
// Done
//
return STATUS_SUCCESS;
}
NTSTATUS
OSNotifyCreatePowerResource(
IN PNSOBJ AcpiObject
)
/*++
Routine Description:
This routine is called whenever a new power resource appears. This routine
is callable at DispatchLevel.
Arguments:
AcpiObject - Pointer to new ACPI Object
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PACPI_POWER_DEVICE_NODE powerNode;
ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
ASSERT( AcpiObject != NULL);
//
// Build the power extension
//
status = ACPIBuildPowerResourceExtension( AcpiObject, &powerNode );
//
// What happened?
//
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSNotifyCreatePowerResource: %p = %08lx\n",
AcpiObject,
status
) );
goto OSNotifyCreatePowerResourceExit;
}
//
// Make sure to request that this node gets processed
//
status = ACPIBuildPowerResourceRequest(
powerNode,
NULL,
NULL,
FALSE
);
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSNotifyCreatePowerResource: "
"ACPIBuildPowerResourceRequest(%p) = %08lx\n",
powerNode,
status
) );
goto OSNotifyCreatePowerResourceExit;
}
OSNotifyCreatePowerResourceExit:
//
// Done
//
return status;
}
NTSTATUS
OSNotifyCreateProcessor(
IN PNSOBJ AcpiObject,
IN ULONGLONG OptionalFlags
)
/*++
Routine Description:
This routine is called whenever a new processor appears. This routine
is callable at DispatchLevel.
Arguments:
AcpiObject - Pointer to the new ACPI object
OptionalFlags - Properties of the Device Extension that should be
set when its created.
Return Value:
NTSTATUS
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension = NULL;
PDEVICE_EXTENSION parentExtension;
PNSOBJ parentObject;
UCHAR index = 0;
ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
ASSERT( AcpiObject != NULL);
//
// Note: ProcessorList is now implicitly protected by the device tree
// lock since we need to acquire that lock before calling this function
//
//
while (ProcessorList[index] && index < ACPI_SUPPORTED_PROCESSORS) {
index++;
}
//
// We must make sure that the current entry is empty...
//
if (index >= ACPI_SUPPORTED_PROCESSORS || ProcessorList[index] != NULL) {
return STATUS_UNSUCCESSFUL;
}
ACPIPrint( (
ACPI_PRINT_LOADING,
"OSNotifyCreateProcessor: Processor Object #%x: %x\n",
index+1,
AcpiObject
) );
//
// Remember that to store where the new processor object is located
//
ProcessorList[index] = AcpiObject;
//
// First, we need a pointer to the parent node
//
parentObject = AcpiObject->pnsParent;
ASSERT( parentObject != NULL );
//
// Grab the device extension associated with the parent. We need
// this information to help link the parent properly into the tree
//
parentExtension = (PDEVICE_EXTENSION) parentObject->Context;
if (parentExtension == NULL) {
//
// In this case, we can assume that the parent extension is the root
// device extension.
//
parentExtension = RootDeviceExtension;
}
ASSERT( parentExtension != NULL );
//
// Now build an extension for the node
//
status = ACPIBuildProcessorExtension(
AcpiObject,
parentExtension,
&deviceExtension,
index
);
if (NT_SUCCESS(status)) {
//
// Incremement the reference count on the node. We do this because
// we are going to be doing work (which will take a long time
// to complete, anyways), and we don't want to hold the lock for that
// entire time. If we incr the reference count, then we guarantee that
// no one can come along and kick the feet out from underneath us
//
InterlockedIncrement( &(deviceExtension->ReferenceCount) );
}
//
// What happend to the creation of the extension?
//
if (!NT_SUCCESS(status)) {
//
// We should have succeeded at whatever we are doing --- so this is
// a bad place to be
//
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSNotifyCreateProcessor: NSObj %p Failed %08lx\n",
AcpiObject,
status
) );
goto OSNotifyCreateProcessorExit;
}
//
// Set the optional flags if there are any
//
ACPIInternalUpdateFlags(
&(deviceExtension->Flags),
OptionalFlags,
FALSE
);
//
// Make sure to queue the request
//
status = ACPIBuildProcessorRequest(
deviceExtension,
NULL,
NULL,
FALSE
);
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSNotifyCreateProcessor: "
"ACPIBuildProcessorRequest(%p) = %08lx\n",
deviceExtension,
status
) );
goto OSNotifyCreateProcessorExit;
}
OSNotifyCreateProcessorExit:
//
// There is some work that will be done later
//
return status;
}
NTSTATUS
OSNotifyCreateThermalZone(
IN PNSOBJ AcpiObject,
IN ULONGLONG OptionalFlags
)
/*++
Routine Description:
This routine is called whenever a new thermal zone appears. This routine is
callable at DispatchLevel.
Arguments:
AcpiObject - Pointer to new ACPI Object
OptionalFlags - Properties of the Device Extension that should be
set when its created.
Return Value:
NTSTATUS
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension = NULL;
ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
ASSERT( AcpiObject != NULL);
//
// Now build an extension for the node
//
status = ACPIBuildThermalZoneExtension(
AcpiObject,
RootDeviceExtension,
&deviceExtension
);
if (NT_SUCCESS(status)) {
//
// Incremement the reference count on the node. We do this because
// we are going to be doing work (which will take a long time
// to complete, anyways), and we don't want to hold the lock for that
// entire time. If we incr the reference count, then we guarantee that
// no one can come along and kick the feet out from underneath us
//
InterlockedIncrement( &(deviceExtension->ReferenceCount) );
}
//
// What happend to the creation of the extension?
//
if (!NT_SUCCESS(status)) {
//
// We should have succeeded at whatever we are doing --- so this is
// a bad place to be
//
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSNotifyCreateThermalZone: NSObj %p Failed %08lx\n",
AcpiObject,
status
) );
goto OSNotifyCreateThermalZoneExit;
}
//
// Set the optional flags if there are any
//
ACPIInternalUpdateFlags(
&(deviceExtension->Flags),
OptionalFlags,
FALSE
);
//
// Make sure to queue the request
//
status = ACPIBuildThermalZoneRequest(
deviceExtension,
NULL,
NULL,
FALSE
);
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSNotifyCreateThermalZone: "
"ACPIBuildThermalZoneRequest(%p) = %08lx\n",
deviceExtension,
status
) );
goto OSNotifyCreateThermalZoneExit;
}
OSNotifyCreateThermalZoneExit:
//
// There is some work that will be done later
//
return status;
}
NTSTATUS
EXPORT
OSNotifyDeviceCheck(
IN PNSOBJ AcpiObject
)
/*++
Routine Description:
This routine is called when the AML Interpreter signals that the
System should check the presence of a device. If the device remains
present, nothing is done. If the device appears or disappears the
appropriate action is taken.
For legacy reasons, if the device is a dock we initiate an undock request.
Newer ACPI BIOS's should use Notify(,3).
Arguments:
AcpiObject - The device we should check for new/missing children.
Return Value:
NTSTATUS
--*/
{
PDEVICE_EXTENSION deviceExtension;
ASSERT( AcpiObject != NULL );
//
// Let the world know
//
ACPIPrint( (
ACPI_PRINT_PNP,
"OSNotifyDeviceCheck: 0x%p (%s)\n",
AcpiObject,
ACPIAmliNameObject( AcpiObject )
) );
deviceExtension = (PDEVICE_EXTENSION) AcpiObject->Context;
if (deviceExtension == NULL) {
return STATUS_SUCCESS;
}
//
// Notify(,1) on a dock node is an eject request request. Handle specially.
//
if (ACPIDockIsDockDevice(AcpiObject)) {
//
// We only let BIOS's get away with this because we rev'd the spec
// after Win98. Both OS's will agree with the release of NT5 and
// Win98 SP1
//
ACPIPrint( (
ACPI_PRINT_WARNING,
"OSNotifyDeviceCheck: BIOS issued Notify(dock,1), should use "
" Notify(dock,3) to request ejection of a dock.\n",
AcpiObject,
ACPIAmliNameObject( AcpiObject )
) );
return OSNotifyDeviceEject(AcpiObject) ;
}
//
// Search for the parent of the first device that the OS is aware, and
// issue a device check notify
//
// N.B.
// There is currently no way in WDM to do a "light" device check. Once
// this is amended, the following code should be updated to do something
// more efficient.
//
deviceExtension = deviceExtension->ParentExtension;
while (deviceExtension) {
if (!(deviceExtension->Flags & DEV_TYPE_NOT_FOUND)) {
//
// Invalid the device relations for this device tree
//
IoInvalidateDeviceRelations(
deviceExtension->PhysicalDeviceObject,
BusRelations
);
break;
}
//
// Try the parent device
//
deviceExtension = deviceExtension->ParentExtension;
}
//
// Done
//
return STATUS_SUCCESS;
}
NTSTATUS
EXPORT
OSNotifyDeviceEnum(
IN PNSOBJ AcpiObject
)
/*++
Routine Description:
This routine is called when the AML Interpreter signals that the
System should re-enumerate the device
Arguments:
AcpiObject - The device we should check for new/missing children.
Return Value:
NTSTATUS
--*/
{
PDEVICE_EXTENSION deviceExtension;
PDEVICE_EXTENSION dockExtension;
ASSERT( AcpiObject != NULL );
//
// Let the world know
//
ACPIPrint( (
ACPI_PRINT_PNP,
"OSNotifyDeviceEnum: 0x%p (%s)\n",
AcpiObject,
ACPIAmliNameObject( AcpiObject )
) );
deviceExtension = (PDEVICE_EXTENSION) AcpiObject->Context;
if (deviceExtension == NULL) {
return STATUS_SUCCESS;
}
//
// Notify(,0) on a dock node is a dock request. Handle specially.
//
if (ACPIDockIsDockDevice(AcpiObject)) {
dockExtension = ACPIDockFindCorrespondingDock( deviceExtension );
if (!dockExtension) {
ACPIPrint( (
ACPI_PRINT_FAILURE,
"OSNotifyDeviceEnum: Dock device 0x%p (%s) "
"does not have a profile provider!\n",
AcpiObject,
ACPIAmliNameObject( AcpiObject )
) );
return STATUS_SUCCESS;
}
//
// If this node is marked "Unknown", move it to "Isolated" as
// Notify(Dock,0) was ran. If we never saw Notify(Dock,0) but the
// dock's _STA said "here", we would assume _DCK(0) was ran by the BIOS
// itself.
//
InterlockedCompareExchange(
(PULONG) &dockExtension->Dock.IsolationState,
IS_ISOLATED,
IS_UNKNOWN
);
if (dockExtension->Dock.IsolationState == IS_ISOLATED) {
if (dockExtension->Flags&DEV_TYPE_NOT_FOUND) {
//
// We haven't made a PDO for the docking station yet. This may
// be a request to bring it online. Mark the profile provider
// so that we notice the new dock appearing
//
ACPIInternalUpdateFlags(
&dockExtension->Flags,
DEV_CAP_UNATTACHED_DOCK,
FALSE
);
}
//
// Invalidate the beginning of the tree. This will cause our fake
// dock node to start.
//
IoInvalidateDeviceRelations(
RootDeviceExtension->PhysicalDeviceObject,
SingleBusRelations
);
}
return STATUS_SUCCESS;
}
//
// Search for the parent of the first device that the OS is aware, and
// issue a device check notify
//
while (deviceExtension) {
if (!(deviceExtension->Flags & DEV_TYPE_NOT_FOUND)) {
//
// Invalid the device relations for this device tree
//
IoInvalidateDeviceRelations(
deviceExtension->PhysicalDeviceObject,
BusRelations
);
break;
}
//
// Try the parent device
//
deviceExtension = deviceExtension->ParentExtension;
}
//
// Done
//
return STATUS_SUCCESS;
}
NTSTATUS
EXPORT
OSNotifyDeviceEject(
IN PNSOBJ AcpiObject
)
/*++
Routine Description:
This routine is called when the device's eject button is pressed
Arguments:
AcpiObject - The device to be ejected
Return Value:
NTSTATUS
--*/
{
PDEVICE_EXTENSION deviceExtension;
ASSERT( AcpiObject != NULL );
//
// Let the world know
//
ACPIPrint( (
ACPI_PRINT_REMOVE,
"OSNotifyDeviceEject: 0x%p (%s)\n",
AcpiObject,
ACPIAmliNameObject( AcpiObject )
) );
//
// Inform the OS of which device wants to go away. If the OS doesn't
// know about the device, then don't bother
//
deviceExtension = (PDEVICE_EXTENSION) AcpiObject->Context;
//
// If this is a dock, queue the eject against the profile provider.
//
if (ACPIDockIsDockDevice(AcpiObject)) {
deviceExtension = ACPIDockFindCorrespondingDock( deviceExtension );
if (!deviceExtension) {
ACPIPrint( (
ACPI_PRINT_FAILURE,
"OSNotifyDeviceEject: Dock device 0x%p (%s) "
"does not have a profile provider!\n",
AcpiObject,
ACPIAmliNameObject( AcpiObject )
) );
return STATUS_SUCCESS;
}
}
if (deviceExtension && !(deviceExtension->Flags & DEV_TYPE_NOT_FOUND)) {
IoRequestDeviceEject (deviceExtension->PhysicalDeviceObject);
}
//
// Done
//
return STATUS_SUCCESS;
}
NTSTATUS
EXPORT
OSNotifyDeviceWake(
IN PNSOBJ AcpiObject
)
/*++
Routine Description:
This is called when a device has woken the computer
Arguments:
AcpiObject - The device which woke the computer
Return Value:
NTSTATUS
--*/
{
KIRQL oldIrql;
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension;
PLIST_ENTRY powerList;
ASSERT( AcpiObject != NULL );
//
// Grab the device extension associated with this NS object
//
deviceExtension = (PDEVICE_EXTENSION) AcpiObject->Context;
ASSERT( deviceExtension != NULL );
//
// Let the world know
//
ACPIDevPrint( (
ACPI_PRINT_WAKE,
deviceExtension,
"OSNotifyDeviceWake - 0x%p (%s)\n",
AcpiObject,
ACPIAmliNameObject( AcpiObject )
) );
//
// Initialize the list that will hold the requests
//
powerList = ExAllocatePoolWithTag(
NonPagedPool,
sizeof(LIST_ENTRY),
ACPI_MISC_POOLTAG
);
if (powerList == NULL) {
ACPIDevPrint( (
ACPI_PRINT_CRITICAL,
deviceExtension,
"OSNotifyDeviceWake - Cannot Allocate LIST_ENTRY\n"
) );
return STATUS_SUCCESS;
}
InitializeListHead( powerList );
//
// Remove the affected requests from the wait list
//
IoAcquireCancelSpinLock( &oldIrql );
KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
ACPIWakeRemoveDevicesAndUpdate( deviceExtension, powerList );
KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
IoReleaseCancelSpinLock( oldIrql );
//
// If the list is non-empty, then disable those requests
//
if (!IsListEmpty( powerList ) ) {
status = ACPIWakeDisableAsync(
deviceExtension,
powerList,
OSNotifyDeviceWakeCallBack,
powerList
);
if (status != STATUS_PENDING) {
OSNotifyDeviceWakeCallBack(
NULL,
status,
NULL,
powerList
);
}
ACPIDevPrint( (
ACPI_PRINT_WAKE,
deviceExtension,
"OSNotifyDeviceWake - ACPIWakeDisableAsync = %08lx\n",
status
) );
} else {
//
// We must free this memory ourselves
//
ExFreePool( powerList );
}
//
// Done
//
return STATUS_SUCCESS;
}
VOID
EXPORT
OSNotifyDeviceWakeCallBack(
IN PNSOBJ AcpiObject,
IN NTSTATUS Status,
IN POBJDATA ObjectData,
IN PVOID Context
)
/*++
Routine Description:
This routine is called when we have completed _PSW(off) on a device
Arguments:
AcpiObject - Points to the control method that was run
Status - Result of the method
ObjectData - Information about the result
Context - P{DEVICE_EXTENSION
Return Value:
NTSTATUS
--*/
{
#if DBG
PACPI_POWER_REQUEST powerRequest;
PDEVICE_EXTENSION deviceExtension;
#endif
PLIST_ENTRY powerList = (PLIST_ENTRY) Context;
//
// Do we have some work to do?
//
if (IsListEmpty( powerList ) ) {
ACPIPrint( (
ACPI_PRINT_WARNING,
"OSNotifyDeviceWakeCallBack: %p is an empty list\n",
powerList
) );
ExFreePool( powerList );
return;
}
#if DBG
//
// Get the first record, so that we have a clue as to the device
// that was completed
//
powerRequest = CONTAINING_RECORD(
powerList->Flink,
ACPI_POWER_REQUEST,
ListEntry
);
ASSERT( powerRequest->Signature == ACPI_SIGNATURE );
//
// Grab the device extension
//
deviceExtension = powerRequest->DeviceExtension;
//
// Tell the world
//
ACPIDevPrint( (
ACPI_PRINT_WAKE,
deviceExtension,
"OSNotifyDeviceWakeCallBack = 0x%08lx\n",
Status
) );
#endif
//
// Complete the requests
//
ACPIWakeCompleteRequestQueue(
powerList,
Status
);
//
// Free the list pointer
//
ExFreePool( powerList );
}
VOID
EXPORT
OSNotifyDeviceWakeByGPEEvent(
IN ULONG GpeIndex,
IN ULONG GpeRegister,
IN ULONG GpeMask
)
/*++
Routine Description:
This is called when a device has woken the computer
Arguments:
GpeIndex - The index bit of the GPE that woke the computer
GpeRegister - The register index
GpeMask - The enabled bits for that register
Return Value:
NTSTATUS
--*/
{
KIRQL oldIrql;
NTSTATUS status;
PACPI_POWER_REQUEST powerRequest;
PDEVICE_EXTENSION deviceExtension;
PLIST_ENTRY listEntry;
PLIST_ENTRY powerList;
//
// Let the world know
//
ACPIPrint( (
ACPI_PRINT_WAKE,
"OSNotifyDeviceWakeByGPEEvent: %02lx[%x] & %02lx\n",
GpeRegister, GpeIndex, GpeMask
) );
//
// Initialize the list that will hold the requests
//
powerList = ExAllocatePoolWithTag(
NonPagedPool,
sizeof(LIST_ENTRY),
ACPI_MISC_POOLTAG
);
if (powerList == NULL) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"OSNotifyDeviceWakeByGPEEvent: Cannot Allocate LIST_ENTRY\n"
) );
return;
}
InitializeListHead( powerList );
//
// We need to be holding these locks
//
IoAcquireCancelSpinLock( &oldIrql );
KeAcquireSpinLockAtDpcLevel( &AcpiPowerLock );
//
// Look for a matching power request for this GPE
//
for (listEntry = AcpiPowerWaitWakeList.Flink;
listEntry != &AcpiPowerWaitWakeList;
listEntry = listEntry->Flink) {
//
// Grab the request
//
powerRequest = CONTAINING_RECORD(
listEntry,
ACPI_POWER_REQUEST,
ListEntry
);
ASSERT( powerRequest->Signature == ACPI_SIGNATURE );
deviceExtension = powerRequest->DeviceExtension;
//
// See if this request matches
//
if (deviceExtension->PowerInfo.WakeBit == GpeIndex) {
//
// Get all of the wait requests for this device
//
ACPIWakeRemoveDevicesAndUpdate( deviceExtension, powerList );
break;
}
}
//
// This is an exclusive wake gpe bit --- verify there are not multiple
// devices waiting for it, as that would be a design which could cause a
// deadlock
//
if (!IsListEmpty( powerList ) ) {
ASSERT( !(GpeWakeEnable[GpeRegister] & GpeMask) );
}
//
// No longer need these locks
//
KeReleaseSpinLockFromDpcLevel( &AcpiPowerLock );
IoReleaseCancelSpinLock( oldIrql );
//
// If the list is non-empty, then disable those requests
//
if (!IsListEmpty( powerList ) ) {
status = ACPIWakeDisableAsync(
deviceExtension,
powerList,
OSNotifyDeviceWakeCallBack,
powerList
);
if (status != STATUS_PENDING) {
OSNotifyDeviceWakeCallBack(
NULL,
status,
NULL,
powerList
);
}
ACPIDevPrint( (
ACPI_PRINT_WAKE,
deviceExtension,
"OSNotifyDeviceWakeByGPEIndex - ACPIWakeDisableAsync = %08lx\n",
status
) );
} else {
//
// We must free this memory ourselves
//
ExFreePool( powerList );
}
//
// Done
//
return;
}
NTSTATUS
EXPORT
OSNotifyFatalError(
IN ULONG Param1,
IN ULONG Param2,
IN ULONG Param3,
IN ULONG_PTR AmlContext,
IN ULONG_PTR Context
)
/*++
Routine Description:
This routine is called whenever the AML code detects a condition that the
machine can no longer handle. It
--*/
{
KIRQL oldIrql;
//
// Acquire the spinlock and see if there is an outstanding fatal error
// pending already
//
KeAcquireSpinLock( &AcpiPowerLock, &oldIrql );
if (AcpiFatalOutstanding != FALSE) {
//
// There is one outstanding already... don't do anything
//
KeReleaseSpinLock( &AcpiPowerLock, oldIrql );
return STATUS_SUCCESS;
}
//
// Remember that there is an outstanding fatal context and release the lock
AcpiFatalOutstanding = TRUE;
KeReleaseSpinLock(&AcpiPowerLock, oldIrql);
//
// Initialize the work queue
//
ExInitializeWorkItem(
&(AcpiFatalContext.Item),
OSNotifyFatalErrorWorker,
&AcpiFatalContext
);
AcpiFatalContext.Param1 = Param1;
AcpiFatalContext.Param2 = Param2;
AcpiFatalContext.Param3 = Param3;
AcpiFatalContext.Context = AmlContext;
//
// Queue the work item and return
//
ExQueueWorkItem( &(AcpiFatalContext.Item), DelayedWorkQueue );
return STATUS_SUCCESS;
}
VOID
OSNotifyFatalErrorWorker(
IN PVOID Context
)
/*++
Routine Description:
This is the routine that actually shuts down the machine on a fatal
error
Arguments:
Context - Points to the fatal error context
Return Value:
None
--*/
{
PACPI_FATAL_ERROR_CONTEXT fatal = (PACPI_FATAL_ERROR_CONTEXT) Context;
#if 0
PWCHAR stringData[1];
ULONG data[3];
//
// Generate the parameters for an error log message
//
stringData[0] = L"Acpi";
data[0] = fatal->Param1;
data[1] = fatal->Param2;
data[2] = fatal->Param3;
//
// Write the error log message
//
ACPIErrLogWriteEventLogEntry(
ACPI_ERR_BIOS_FATAL,
0,
1,
&stringData,
sizeof(ULONG) * 3,
data
);
#else
//
// Now, we can bugcheck
//
PoShutdownBugCheck(
TRUE,
ACPI_BIOS_FATAL_ERROR,
fatal->Param1,
fatal->Param2,
fatal->Param3,
fatal->Context
);
#endif
}