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