831 lines
19 KiB
C
831 lines
19 KiB
C
/*++
|
||
|
||
Copyright (c) 1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
acpiosnt.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the OS specific functions for the Windows NT
|
||
version of the ACPI driver
|
||
|
||
Author:
|
||
|
||
Jason Clark (jasoncl)
|
||
Stephane Plante (splante)
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
09-Oct-96 Initial Revision
|
||
20-Nov-96 Interrupt Vector support
|
||
31-Mar-97 Cleanup
|
||
|
||
--*/
|
||
|
||
#include "pch.h"
|
||
#include "amlihook.h"
|
||
|
||
// from shared\acpiinit.c
|
||
extern PACPIInformation AcpiInformation;
|
||
|
||
// from irqarb.c
|
||
extern ULONG InterruptModel;
|
||
|
||
NTSTATUS
|
||
DriverEntry (
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
);
|
||
|
||
PPM_DISPATCH_TABLE PmHalDispatchTable;
|
||
FAST_IO_DISPATCH ACPIFastIoDispatch;
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(INIT,DriverEntry)
|
||
#pragma alloc_text(PAGE,OSInterruptVector)
|
||
#pragma alloc_text(PAGE,NotifyHalWithMachineStates)
|
||
#endif
|
||
|
||
ACPI_HAL_DISPATCH_TABLE AcpiHalDispatchTable;
|
||
|
||
NTSTATUS
|
||
DriverEntry (
|
||
PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The ACPI driver's entry point
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to the object that represents this driver
|
||
|
||
Return Value:
|
||
|
||
N/A
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
ULONG i;
|
||
ULONG argSize;
|
||
|
||
//
|
||
// If the AMLIHOOK interface is enabled
|
||
// hook it.
|
||
//
|
||
|
||
AmliHook_InitTestHookInterface();
|
||
|
||
//
|
||
// Remember the name of the driver object
|
||
//
|
||
AcpiDriverObject = DriverObject;
|
||
|
||
//
|
||
// Save registry path for use by WMI registration code
|
||
//
|
||
AcpiRegistryPath.Length = 0;
|
||
AcpiRegistryPath.MaximumLength = RegistryPath->Length + sizeof(WCHAR);
|
||
AcpiRegistryPath.Buffer = ExAllocatePoolWithTag(
|
||
PagedPool,
|
||
RegistryPath->Length+sizeof(WCHAR),
|
||
ACPI_MISC_POOLTAG
|
||
);
|
||
if (AcpiRegistryPath.Buffer != NULL) {
|
||
RtlCopyUnicodeString(&AcpiRegistryPath, RegistryPath);
|
||
|
||
} else {
|
||
|
||
AcpiRegistryPath.MaximumLength = 0;
|
||
|
||
}
|
||
|
||
//
|
||
// Read the keys that we need to operate this driver from the
|
||
// registry
|
||
//
|
||
ACPIInitReadRegistryKeys();
|
||
|
||
//
|
||
// This flag may be set, when its not required, nor desired
|
||
// so take the opportunity to clean it up now
|
||
//
|
||
if (AcpiOverrideAttributes & ACPI_OVERRIDE_MP_SLEEP) {
|
||
|
||
KAFFINITY processors = KeQueryActiveProcessors();
|
||
|
||
//
|
||
// If this is a UP system, then turn off this override
|
||
//
|
||
if (processors == 1) {
|
||
|
||
AcpiOverrideAttributes &= ~ACPI_OVERRIDE_MP_SLEEP;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Initialize the DPCs
|
||
//
|
||
KeInitializeDpc( &AcpiPowerDpc, ACPIDevicePowerDpc, NULL );
|
||
KeInitializeDpc( &AcpiBuildDpc, ACPIBuildDeviceDpc, NULL );
|
||
KeInitializeDpc( &AcpiGpeDpc, ACPIInterruptDispatchEventDpc, NULL );
|
||
|
||
//
|
||
// Initialize the timer
|
||
//
|
||
KeInitializeTimer( &AcpiGpeTimer );
|
||
|
||
//
|
||
// Initialize the SpinLocks
|
||
//
|
||
KeInitializeSpinLock( &AcpiDeviceTreeLock );
|
||
KeInitializeSpinLock( &AcpiPowerLock );
|
||
KeInitializeSpinLock( &AcpiPowerQueueLock );
|
||
KeInitializeSpinLock( &AcpiBuildQueueLock );
|
||
KeInitializeSpinLock( &AcpiThermalLock );
|
||
KeInitializeSpinLock( &AcpiButtonLock );
|
||
KeInitializeSpinLock( &AcpiFatalLock );
|
||
KeInitializeSpinLock( &AcpiUpdateFlagsLock );
|
||
KeInitializeSpinLock( &AcpiGetLock );
|
||
|
||
//
|
||
// Initialize the List Entry's
|
||
//
|
||
InitializeListHead( &AcpiPowerDelayedQueueList );
|
||
InitializeListHead( &AcpiPowerQueueList );
|
||
InitializeListHead( &AcpiPowerPhase0List );
|
||
InitializeListHead( &AcpiPowerPhase1List );
|
||
InitializeListHead( &AcpiPowerPhase2List );
|
||
InitializeListHead( &AcpiPowerPhase3List );
|
||
InitializeListHead( &AcpiPowerPhase4List );
|
||
InitializeListHead( &AcpiPowerPhase5List );
|
||
InitializeListHead( &AcpiPowerWaitWakeList );
|
||
InitializeListHead( &AcpiPowerSynchronizeList );
|
||
InitializeListHead( &AcpiPowerNodeList );
|
||
InitializeListHead( &AcpiBuildQueueList );
|
||
InitializeListHead( &AcpiBuildDeviceList );
|
||
InitializeListHead( &AcpiBuildOperationRegionList );
|
||
InitializeListHead( &AcpiBuildPowerResourceList );
|
||
InitializeListHead( &AcpiBuildRunMethodList );
|
||
InitializeListHead( &AcpiBuildSynchronizationList );
|
||
InitializeListHead( &AcpiBuildThermalZoneList );
|
||
InitializeListHead( &AcpiUnresolvedEjectList );
|
||
InitializeListHead( &AcpiThermalList );
|
||
InitializeListHead( &AcpiButtonList );
|
||
InitializeListHead( &AcpiGetListEntry );
|
||
|
||
//
|
||
// Initialize the variables/booleans
|
||
//
|
||
AcpiPowerDpcRunning = FALSE;
|
||
AcpiPowerWorkDone = FALSE;
|
||
AcpiBuildDpcRunning = FALSE;
|
||
AcpiBuildFixedButtonEnumerated = FALSE;
|
||
AcpiBuildWorkDone = FALSE;
|
||
AcpiFatalOutstanding = FALSE;
|
||
AcpiGpeDpcRunning = FALSE;
|
||
AcpiGpeDpcScheduled = FALSE;
|
||
AcpiGpeWorkDone = FALSE;
|
||
|
||
//
|
||
// Initialize the LookAside lists.
|
||
//
|
||
ExInitializeNPagedLookasideList(
|
||
&BuildRequestLookAsideList,
|
||
NULL,
|
||
NULL,
|
||
0,
|
||
sizeof(ACPI_BUILD_REQUEST),
|
||
ACPI_DEVICE_POOLTAG,
|
||
(PAGE_SIZE / sizeof(ACPI_BUILD_REQUEST) )
|
||
);
|
||
ExInitializeNPagedLookasideList(
|
||
&RequestLookAsideList,
|
||
NULL,
|
||
NULL,
|
||
0,
|
||
sizeof(ACPI_POWER_REQUEST),
|
||
ACPI_POWER_POOLTAG,
|
||
(PAGE_SIZE * 4 / sizeof(ACPI_POWER_REQUEST) )
|
||
);
|
||
ExInitializeNPagedLookasideList(
|
||
&DeviceExtensionLookAsideList,
|
||
NULL,
|
||
NULL,
|
||
0,
|
||
sizeof(DEVICE_EXTENSION),
|
||
ACPI_DEVICE_POOLTAG,
|
||
64
|
||
);
|
||
ExInitializeNPagedLookasideList(
|
||
&ObjectDataLookAsideList,
|
||
NULL,
|
||
NULL,
|
||
0,
|
||
sizeof(OBJDATA),
|
||
ACPI_OBJECT_POOLTAG,
|
||
(PAGE_SIZE / sizeof(OBJDATA) )
|
||
);
|
||
ExInitializeNPagedLookasideList(
|
||
&PswContextLookAsideList,
|
||
NULL,
|
||
NULL,
|
||
0,
|
||
sizeof(ACPI_WAKE_PSW_CONTEXT),
|
||
ACPI_POWER_POOLTAG,
|
||
16
|
||
);
|
||
|
||
//
|
||
// Initialize internal worker
|
||
//
|
||
ACPIInitializeWorker ();
|
||
|
||
//
|
||
// Make sure that we have an AddDevice function that will create
|
||
// the basic FDO for this device when it is called
|
||
//
|
||
DriverObject->DriverExtension->AddDevice = ACPIDispatchAddDevice;
|
||
|
||
//
|
||
// All irps will be sent through a single dispatch point
|
||
//
|
||
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
|
||
|
||
DriverObject->MajorFunction[ i ] = ACPIDispatchIrp;
|
||
|
||
}
|
||
DriverObject->DriverUnload = ACPIUnload;
|
||
|
||
//
|
||
// Fill out the Fast Io Detach callback for our bus filter
|
||
//
|
||
RtlZeroMemory(&ACPIFastIoDispatch, sizeof(FAST_IO_DISPATCH)) ;
|
||
ACPIFastIoDispatch.SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH) ;
|
||
ACPIFastIoDispatch.FastIoDetachDevice = ACPIFilterFastIoDetachCallback ;
|
||
DriverObject->FastIoDispatch = &ACPIFastIoDispatch ;
|
||
|
||
//
|
||
// Initialize some HAL stuff
|
||
//
|
||
AcpiHalDispatchTable.Signature = ACPI_HAL_DISPATCH_SIGNATURE;
|
||
AcpiHalDispatchTable.Version = ACPI_HAL_DISPATCH_VERSION;
|
||
AcpiHalDispatchTable.AcpipEnableDisableGPEvents =
|
||
&ACPIGpeHalEnableDisableEvents;
|
||
AcpiHalDispatchTable.AcpipInitEnableAcpi =
|
||
&ACPIEnableInitializeACPI;
|
||
AcpiHalDispatchTable.AcpipGpeEnableWakeEvents =
|
||
&ACPIWakeEnableWakeEvents;
|
||
HalInitPowerManagement(
|
||
(PPM_DISPATCH_TABLE)(&AcpiHalDispatchTable),
|
||
&PmHalDispatchTable
|
||
);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
VOID
|
||
OSInitializeCallbacks(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called right after the interper has been initialized,
|
||
but before AML code has actually been executed.
|
||
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
POPREGIONHANDLER dummy;
|
||
#if DBG
|
||
NTSTATUS status;
|
||
|
||
status =
|
||
#endif
|
||
AMLIRegEventHandler(
|
||
EVTYPE_OPCODE_EX,
|
||
OP_LOAD,
|
||
ACPICallBackLoad,
|
||
0
|
||
);
|
||
#if DBG
|
||
if (!NT_SUCCESS(status)) {
|
||
ACPIBreakPoint();
|
||
}
|
||
|
||
status =
|
||
#endif
|
||
AMLIRegEventHandler(
|
||
EVTYPE_OPCODE_EX,
|
||
OP_UNLOAD,
|
||
ACPICallBackUnload,
|
||
0
|
||
);
|
||
#if DBG
|
||
if (!NT_SUCCESS(status)) {
|
||
ACPIBreakPoint();
|
||
}
|
||
|
||
status =
|
||
#endif
|
||
AMLIRegEventHandler(
|
||
EVTYPE_DESTROYOBJ,
|
||
0,
|
||
(PFNHND)ACPITableNotifyFreeObject,
|
||
0
|
||
);
|
||
#if DBG
|
||
if (!NT_SUCCESS(status)) {
|
||
ACPIBreakPoint();
|
||
}
|
||
|
||
status =
|
||
#endif
|
||
AMLIRegEventHandler(
|
||
EVTYPE_NOTIFY,
|
||
0,
|
||
NotifyHandler,
|
||
0
|
||
);
|
||
#if DBG
|
||
if (!NT_SUCCESS(status)) {
|
||
ACPIBreakPoint();
|
||
}
|
||
|
||
status =
|
||
#endif
|
||
AMLIRegEventHandler(
|
||
EVTYPE_ACQREL_GLOBALLOCK,
|
||
0,
|
||
GlobalLockEventHandler,
|
||
0
|
||
);
|
||
#if DBG
|
||
if (!NT_SUCCESS(status)) {
|
||
ACPIBreakPoint();
|
||
}
|
||
|
||
status =
|
||
#endif
|
||
AMLIRegEventHandler(
|
||
EVTYPE_CREATE,
|
||
0,
|
||
OSNotifyCreate,
|
||
0
|
||
);
|
||
#if DBG
|
||
if (!NT_SUCCESS(status)) {
|
||
ACPIBreakPoint();
|
||
}
|
||
|
||
status =
|
||
#endif
|
||
AMLIRegEventHandler(
|
||
EVTYPE_FATAL,
|
||
0,
|
||
OSNotifyFatalError,
|
||
0
|
||
);
|
||
#if DBG
|
||
if (!NT_SUCCESS(status)) {
|
||
ACPIBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Register internal support of PCI operational regions. Note that
|
||
// we don't specify a region object here because we haven't yet created it
|
||
//
|
||
RegisterOperationRegionHandler(
|
||
NULL,
|
||
EVTYPE_RS_COOKACCESS,
|
||
REGSPACE_PCICFG, // PCI config space
|
||
(PFNHND)PciConfigSpaceHandler,
|
||
0,
|
||
&dummy);
|
||
}
|
||
|
||
BOOLEAN
|
||
OSInterruptVector(
|
||
PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is charged with claiming an Interrupt for the device
|
||
|
||
Arguments:
|
||
|
||
Context - Context Pointer (points to FDO currently)
|
||
|
||
Return
|
||
|
||
TRUE for success
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptDesc;
|
||
ULONG Count;
|
||
|
||
PAGED_CODE();
|
||
|
||
deviceExtension = ACPIInternalGetDeviceExtension( (PDEVICE_OBJECT) Context );
|
||
|
||
//
|
||
// Grab the translated interrupt vector from our resource list
|
||
//
|
||
Count = 0;
|
||
InterruptDesc = RtlUnpackPartialDesc(
|
||
CmResourceTypeInterrupt,
|
||
deviceExtension->ResourceList,
|
||
&Count
|
||
);
|
||
if (InterruptDesc == NULL) {
|
||
|
||
ACPIDevPrint( (
|
||
ACPI_PRINT_CRITICAL,
|
||
deviceExtension,
|
||
" - Could not find interrupt descriptor\n"
|
||
) );
|
||
KeBugCheckEx(
|
||
ACPI_BIOS_ERROR,
|
||
ACPI_ROOT_RESOURCES_FAILURE,
|
||
(ULONG_PTR) deviceExtension,
|
||
(ULONG_PTR) deviceExtension->ResourceList,
|
||
1
|
||
);
|
||
|
||
}
|
||
|
||
//
|
||
// Initialize our DPC object
|
||
//
|
||
KeInitializeDpc(
|
||
&(deviceExtension->Fdo.InterruptDpc),
|
||
ACPIInterruptServiceRoutineDPC,
|
||
deviceExtension
|
||
);
|
||
|
||
//
|
||
// Now, lets connect ourselves to the interrupt
|
||
//
|
||
status = IoConnectInterrupt(
|
||
&(deviceExtension->Fdo.InterruptObject),
|
||
(PKSERVICE_ROUTINE) ACPIInterruptServiceRoutine,
|
||
deviceExtension,
|
||
NULL,
|
||
InterruptDesc->u.Interrupt.Vector,
|
||
(KIRQL)InterruptDesc->u.Interrupt.Level,
|
||
(KIRQL)InterruptDesc->u.Interrupt.Level,
|
||
LevelSensitive,
|
||
CmResourceShareShared,
|
||
InterruptDesc->u.Interrupt.Affinity,
|
||
FALSE
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
ACPIPrint( (
|
||
ACPI_PRINT_CRITICAL,
|
||
"OSInterruptVector: Could not connected to interrupt - %#08lx\n",
|
||
status
|
||
) );
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Tell the HAL directly that we are done with the interrupt init
|
||
// stuff and it can start using the ACPI timer.
|
||
//
|
||
HalAcpiTimerInit(0,0);
|
||
|
||
//
|
||
// Done
|
||
//
|
||
return (TRUE);
|
||
}
|
||
|
||
VOID
|
||
ACPIAssert (
|
||
ULONG Condition,
|
||
ULONG ErrorCode,
|
||
PCHAR ReplacementText,
|
||
PCHAR SupplementalText,
|
||
ULONG Flags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is called to allow OS specific code to perform some additional OS
|
||
specific processing for Asserts. After this function returns, the normal
|
||
ASSERT macro will be called
|
||
|
||
Arguments:
|
||
|
||
Condition
|
||
ErrorCode
|
||
ReplacementText
|
||
SupplementalText
|
||
Flags
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
--*/
|
||
{
|
||
if (!Condition) {
|
||
|
||
ACPIPrint( (
|
||
ACPI_PRINT_CRITICAL,
|
||
"ACPIAssert: \n"
|
||
" ErrorCode = %08lx Flags = %08lx\n"
|
||
" ReplacmentText = %s\n"
|
||
" SupplmentalText = %s\n",
|
||
ErrorCode, Flags,
|
||
ReplacementText,
|
||
SupplementalText
|
||
) );
|
||
ASSERT(Condition);
|
||
|
||
}
|
||
return;
|
||
}
|
||
|
||
PNSOBJ
|
||
OSConvertDeviceHandleToPNSOBJ(
|
||
PVOID DeviceHandle
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function converts a DeviceHandle (which will always be a
|
||
DeviceObject on NT) to a PNSObj handle.
|
||
|
||
Arguments:
|
||
|
||
DeviceHandle -- A DeviceObject whose PNSOBJ we want to determine.
|
||
|
||
Return Value:
|
||
|
||
The PNSOBJ for the given DeviceHandle or NULL if the conversion
|
||
could not be done.
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_OBJECT deviceObject;
|
||
PDEVICE_EXTENSION deviceExtension;
|
||
|
||
deviceObject = (PDEVICE_OBJECT) DeviceHandle;
|
||
ASSERT( deviceObject != NULL );
|
||
if (deviceObject == NULL) {
|
||
|
||
return (NULL);
|
||
|
||
}
|
||
|
||
deviceExtension = ACPIInternalGetDeviceExtension(deviceObject);
|
||
ASSERT( deviceExtension != NULL );
|
||
if (deviceExtension == NULL) {
|
||
|
||
return (NULL);
|
||
|
||
}
|
||
|
||
return deviceExtension->AcpiObject;
|
||
}
|
||
|
||
NTSTATUS
|
||
NotifyHalWithMachineStates(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine marshals the information about C states and
|
||
S states that the HAL needs and then passes it down.
|
||
|
||
Arguments:
|
||
|
||
none
|
||
|
||
Return Value:
|
||
|
||
status
|
||
|
||
--*/
|
||
{
|
||
BOOLEAN overrideMpSleep = FALSE;
|
||
CHAR picMethod[] = "\\_PIC";
|
||
NTSTATUS status;
|
||
OBJDATA data;
|
||
PHAL_SLEEP_VAL sleepVals = NULL;
|
||
PNSOBJ pnsobj = NULL;
|
||
PUCHAR SleepState[] = { "\\_S1", "\\_S2", "\\_S3",
|
||
"\\_S4", "\\_S5" };
|
||
SYSTEM_POWER_STATE systemState;
|
||
UCHAR processor = 0;
|
||
UCHAR state;
|
||
ULONG flags = 0;
|
||
ULONG pNum = 0;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Notify the HAL with the location of the PBLKs
|
||
//
|
||
while(ProcessorList[pNum] && pNum < ACPI_SUPPORTED_PROCESSORS) {
|
||
|
||
//
|
||
// find the number of processors
|
||
//
|
||
pNum++;
|
||
|
||
}
|
||
|
||
ACPIPrint( (
|
||
ACPI_PRINT_LOADING,
|
||
"NotifyHalWithMachineStates: Number of processors is %d\n",
|
||
pNum
|
||
) );
|
||
|
||
sleepVals = ExAllocatePoolWithTag(
|
||
NonPagedPool,
|
||
sizeof(HAL_SLEEP_VAL) * 5,
|
||
ACPI_MISC_POOLTAG
|
||
);
|
||
|
||
if (!sleepVals) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
//
|
||
// If there are more than 1 processors (ie: this is an MP machine)
|
||
// and the OverrideMpSleep attribute is set, then we should remember that
|
||
// so that we disallow all S-States other than S0, S4, and S5
|
||
//
|
||
if (AcpiOverrideAttributes & ACPI_OVERRIDE_MP_SLEEP) {
|
||
|
||
overrideMpSleep = TRUE;
|
||
}
|
||
|
||
//
|
||
// Remember that the only s-states that we support are S0, S4, and S5,
|
||
// by default
|
||
//
|
||
AcpiSupportedSystemStates =
|
||
(1 << PowerSystemWorking) +
|
||
(1 << PowerSystemHibernate) +
|
||
(1 << PowerSystemShutdown);
|
||
|
||
//
|
||
// Get the values that the HAL needs for sleeping the machine
|
||
// for each sleep state that this machine supports.
|
||
//
|
||
for (systemState = PowerSystemSleeping1, state = 0;
|
||
state < 5;
|
||
systemState++, state++) {
|
||
|
||
if ( ( (systemState == PowerSystemSleeping1) &&
|
||
(AcpiOverrideAttributes & ACPI_OVERRIDE_DISABLE_S1) ) ||
|
||
( (systemState == PowerSystemSleeping2) &&
|
||
(AcpiOverrideAttributes & ACPI_OVERRIDE_DISABLE_S2) ) ||
|
||
( (systemState == PowerSystemSleeping3) &&
|
||
(AcpiOverrideAttributes & ACPI_OVERRIDE_DISABLE_S3) )) {
|
||
|
||
ACPIPrint( (
|
||
ACPI_PRINT_LOADING,
|
||
"ACPI: SleepState %s disabled due to override\n",
|
||
SleepState[state]
|
||
) );
|
||
sleepVals[state].Supported = FALSE;
|
||
continue;
|
||
|
||
}
|
||
|
||
status = AMLIGetNameSpaceObject(SleepState[state], NULL, &pnsobj, 0);
|
||
if ( !NT_SUCCESS(status) ) {
|
||
|
||
ACPIPrint( (
|
||
ACPI_PRINT_LOADING,
|
||
"ACPI: SleepState %s not supported\n",
|
||
SleepState[state]
|
||
) );
|
||
sleepVals[state].Supported = FALSE;
|
||
continue;
|
||
|
||
}
|
||
if (overrideMpSleep && systemState < PowerSystemHibernate) {
|
||
|
||
ACPIPrint( (
|
||
ACPI_PRINT_WARNING,
|
||
"ACPI: SleepState %s not supported due to override\n",
|
||
SleepState[state]
|
||
) );
|
||
sleepVals[state].Supported = FALSE;
|
||
continue;
|
||
|
||
}
|
||
|
||
//
|
||
// Remember that we support this state
|
||
//
|
||
AcpiSupportedSystemStates |= (1 << systemState);
|
||
sleepVals[state].Supported = TRUE;
|
||
|
||
//
|
||
// Retrieve the value that will be written into the SLP_TYPa
|
||
// register.
|
||
//
|
||
AMLIEvalPackageElement (pnsobj, 0, &data);
|
||
sleepVals[state].Pm1aVal = (UCHAR)data.uipDataValue;
|
||
AMLIFreeDataBuffs(&data, 1);
|
||
|
||
//
|
||
// Retriece the value that will be written in to the SLp_TYPb
|
||
// register
|
||
//
|
||
AMLIEvalPackageElement (pnsobj, 1, &data);
|
||
sleepVals[state].Pm1bVal = (UCHAR)data.uipDataValue;
|
||
AMLIFreeDataBuffs(&data, 1);
|
||
|
||
}
|
||
|
||
//
|
||
// Notify the HAL
|
||
//
|
||
HalAcpiMachineStateInit(NULL, sleepVals, &InterruptModel);
|
||
|
||
ExFreePool(sleepVals);
|
||
|
||
//
|
||
// Notify the namespace with the _PIC val.
|
||
//
|
||
if (InterruptModel > 0) {
|
||
|
||
status = AMLIGetNameSpaceObject(picMethod,NULL,&pnsobj,0);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// The OEM didn't supply a _PIC method. That's OK.
|
||
// We'll assume that IRQ will somehow work without it.
|
||
//
|
||
return status;
|
||
}
|
||
|
||
RtlZeroMemory(&data, sizeof(data));
|
||
data.dwDataType = OBJTYPE_INTDATA;
|
||
data.uipDataValue = InterruptModel;
|
||
|
||
status = AMLIEvalNameSpaceObject(pnsobj, NULL, 1, &data);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Failure to evaluate the _PIC method is not OK.
|
||
//
|
||
KeBugCheckEx(
|
||
ACPI_BIOS_ERROR,
|
||
ACPI_FAILED_PIC_METHOD,
|
||
InterruptModel,
|
||
status,
|
||
(ULONG_PTR) pnsobj
|
||
);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Done
|
||
//
|
||
return status;
|
||
}
|