249 lines
4.6 KiB
C
249 lines
4.6 KiB
C
/*++
|
||
|
||
Copyright (c) 1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
acpienbl.c
|
||
|
||
Abstract:
|
||
|
||
This module contains functions to put an ACPI machine in ACPI mode.
|
||
|
||
Author:
|
||
|
||
Jason Clark (jasoncl)
|
||
|
||
Environment:
|
||
|
||
NT Kernel Model Driver only
|
||
|
||
--*/
|
||
|
||
#include "pch.h"
|
||
|
||
|
||
VOID
|
||
ACPIEnableEnterACPIMode (
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to enter ACPI mode
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
|
||
ULONG i;
|
||
|
||
ASSERTMSG(
|
||
"ACPIEnableEnterACPIMode: System already in ACPI mode!\n",
|
||
!(READ_PM1_CONTROL() & PM1_SCI_EN)
|
||
);
|
||
|
||
//
|
||
// Let the world know about this
|
||
//
|
||
ACPIPrint( (
|
||
ACPI_PRINT_LOADING,
|
||
"ACPIEnableEnterACPIMode: Enabling ACPI\n"
|
||
) );
|
||
|
||
//
|
||
// Write the magic value to the port
|
||
//
|
||
|
||
WRITE_ACPI_REGISTER(SMI_CMD, 0,
|
||
AcpiInformation->FixedACPIDescTable->acpi_on_value);
|
||
|
||
//
|
||
// Make sure that we see that PM1 is in fact enabled
|
||
//
|
||
for (i = 0; ; i++) {
|
||
|
||
if ( (READ_PM1_CONTROL() & PM1_SCI_EN) ) {
|
||
|
||
break;
|
||
|
||
}
|
||
if (i > 0xFFFFFF) {
|
||
|
||
KeBugCheckEx(
|
||
ACPI_BIOS_ERROR,
|
||
ACPI_SYSTEM_CANNOT_START_ACPI,
|
||
6,
|
||
0,
|
||
0
|
||
);
|
||
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
VOID
|
||
ACPIEnableInitializeACPI(
|
||
IN BOOLEAN ReEnable
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
A function to put an ACPI machine into ACPI mode. This function should be
|
||
called with the SCI IRQ masked since we cannot set the interrupt enable
|
||
mask until after enabling ACPI. The SCI should be unmasked by the caller
|
||
when the call returns.
|
||
|
||
General Sequence:
|
||
Enable ACPI through the SMI command port
|
||
Clear the PM1_STS register to put it in a known state
|
||
Set the PM1_EN register mask
|
||
Build the GP mask
|
||
Clear the GP status register bits which belong to the GP mask
|
||
Set the GP enable register bits according to the GP mask built above
|
||
Set the PM1_CTRL register bits.
|
||
|
||
Arguments:
|
||
|
||
NONE
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
--*/
|
||
|
||
{
|
||
USHORT contents;
|
||
USHORT clearbits;
|
||
|
||
//
|
||
// Read PM1_CTRL, if SCI_EN is already set then this is an ACPI only machine
|
||
// and we do not need to Enable ACPI
|
||
//
|
||
if ( !(READ_PM1_CONTROL() & PM1_SCI_EN) ) {
|
||
|
||
AcpiInformation->ACPIOnly = FALSE;
|
||
ACPIEnableEnterACPIMode();
|
||
|
||
}
|
||
|
||
//
|
||
// Put the pm1 status registers into a known state. We will allow the Bus
|
||
// Master bit to be enabled (if we have no choice) across this reset. I do
|
||
// not pretend to understand this code
|
||
//
|
||
CLEAR_PM1_STATUS_REGISTER();
|
||
contents = (USHORT)(READ_PM1_STATUS() & ~(PM1_BM_STS | PM1_RTC_STS));
|
||
if (contents) {
|
||
|
||
CLEAR_PM1_STATUS_REGISTER();
|
||
contents = (USHORT)(READ_PM1_STATUS() & ~(PM1_BM_STS | PM1_RTC_STS));
|
||
|
||
}
|
||
ASSERTMSG(
|
||
"ACPIEnableInitializeACPI: Cannot clear PM1 Status Register\n",
|
||
(contents == 0)
|
||
);
|
||
|
||
//
|
||
// We determined what the PM1 enable bits are when we processed the FADT.
|
||
// We should now enable those bits
|
||
//
|
||
WRITE_PM1_ENABLE( AcpiInformation->pm1_en_bits );
|
||
ASSERTMSG(
|
||
"ACPIEnableInitializeACPI: Cannot write all PM1 Enable Bits\n",
|
||
(READ_PM1_ENABLE() == AcpiInformation->pm1_en_bits)
|
||
);
|
||
|
||
//
|
||
// This is called when we renable ACPI after having woken up from sleep
|
||
// or hibernate
|
||
//
|
||
if (ReEnable) {
|
||
|
||
//
|
||
// Re-enable all possible GPE events
|
||
//
|
||
ACPIGpeClearRegisters();
|
||
ACPIGpeEnableDisableEvents( TRUE );
|
||
|
||
}
|
||
|
||
//
|
||
// Calculate the bits that we should clear. These are the
|
||
// sleep enable bit and the bus master bit.
|
||
//
|
||
// [vincentg] - the original implementation cleared SLP_TYP as well -
|
||
// this breaks C2/C3 on Intel PIIX4 chipsets. Updated to only clear
|
||
// SLP_EN and BM_RLD.
|
||
//
|
||
|
||
clearbits = ((0x8 << SLP_TYP_POS) | PM1_BM_RLD);
|
||
|
||
//
|
||
// Read the PM1 control registery, clear the unwanted bits and then
|
||
// write it back
|
||
//
|
||
contents = (READ_PM1_CONTROL() & ~clearbits);
|
||
WRITE_PM1_CONTROL ( contents, TRUE, WRITE_REGISTER_A_AND_B );
|
||
}
|
||
|
||
VOID
|
||
ACPIEnablePMInterruptOnly(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Descrition:
|
||
|
||
Enable interrupts in the ACPI controller
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
WRITE_PM1_ENABLE(AcpiInformation->pm1_en_bits);
|
||
}
|
||
|
||
ULONG
|
||
ACPIEnableQueryFixedEnables (
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Descrition:
|
||
|
||
Returns the enable mask
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
return AcpiInformation->pm1_en_bits;
|
||
}
|
||
|
||
|