You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
697 lines
17 KiB
697 lines
17 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
acpiio.c
|
|
|
|
Abstract:
|
|
|
|
ACPI OS Independent I/O routines
|
|
|
|
Author:
|
|
|
|
Jason Clark (JasonCl)
|
|
Stephane Plante (SPlante)
|
|
|
|
Environment:
|
|
|
|
NT Kernel Model Driver only
|
|
|
|
Revision History:
|
|
|
|
Eric Nelson - Add Def[ault]Read/Write routines
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
//
|
|
// This driver is not in alpha or beta stages any more --- we can save some
|
|
// CPU calls if we simply define the debug function to nothing
|
|
//
|
|
#define DebugTraceIO(Write, Port, Length, Value )
|
|
static UCHAR IOTrace = 0;
|
|
|
|
VOID
|
|
ACPIIoDebugTrace(
|
|
BOOLEAN Write,
|
|
PUSHORT Port,
|
|
UCHAR Length,
|
|
ULONG Value
|
|
)
|
|
{
|
|
if (IOTrace != 0) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_IO,
|
|
"%x byte %s port 0x%x value %x\n",
|
|
Length, Write ? "WRITE" : "READ", Port, Value
|
|
) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ULONG
|
|
ACPIIoReadPm1Status(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads the PM1 Status registers and masks off any bits that
|
|
we don't care about. This is done because some of these bits are actually
|
|
owned by the HAL
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
ULONG
|
|
|
|
--*/
|
|
{
|
|
|
|
return READ_PM1_STATUS() &
|
|
(AcpiInformation->pm1_en_bits | PM1_WAK_STS | PM1_TMR_STS | PM1_RTC_STS);
|
|
}
|
|
|
|
|
|
VOID
|
|
CLEAR_PM1_STATUS_BITS (
|
|
USHORT BitMask
|
|
)
|
|
{
|
|
if (AcpiInformation->PM1a_BLK != 0) {
|
|
|
|
WRITE_ACPI_REGISTER(PM1a_STATUS, 0, BitMask);
|
|
|
|
DebugTraceIO(
|
|
TRUE,
|
|
(PUSHORT)(AcpiInformation->PM1a_BLK+PM1_STS_OFFSET),
|
|
sizeof(USHORT),
|
|
BitMask
|
|
);
|
|
|
|
}
|
|
if (AcpiInformation->PM1b_BLK != 0) {
|
|
|
|
WRITE_ACPI_REGISTER(PM1b_STATUS, 0, BitMask);
|
|
|
|
DebugTraceIO(
|
|
TRUE,
|
|
(PUSHORT)(AcpiInformation->PM1b_BLK+PM1_STS_OFFSET),
|
|
sizeof(USHORT),
|
|
BitMask
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CLEAR_PM1_STATUS_REGISTER (
|
|
VOID
|
|
)
|
|
{
|
|
USHORT Value = 0;
|
|
|
|
if (AcpiInformation->PM1a_BLK != 0) {
|
|
|
|
Value = READ_ACPI_REGISTER(PM1a_STATUS, 0);
|
|
WRITE_ACPI_REGISTER(PM1a_STATUS, 0, Value);
|
|
|
|
DebugTraceIO(
|
|
TRUE,
|
|
(PUSHORT)(AcpiInformation->PM1a_BLK+PM1_STS_OFFSET),
|
|
sizeof(USHORT),
|
|
Value
|
|
);
|
|
|
|
}
|
|
|
|
if (AcpiInformation->PM1b_BLK != 0) {
|
|
|
|
Value = READ_ACPI_REGISTER(PM1b_STATUS, 0);
|
|
WRITE_ACPI_REGISTER(PM1b_STATUS, 0, Value);
|
|
|
|
DebugTraceIO(
|
|
TRUE,
|
|
(PUSHORT)(AcpiInformation->PM1b_BLK+PM1_STS_OFFSET),
|
|
sizeof(USHORT),
|
|
Value
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
USHORT
|
|
READ_PM1_CONTROL(
|
|
VOID
|
|
)
|
|
{
|
|
USHORT pm1=0;
|
|
|
|
if (AcpiInformation->PM1a_CTRL_BLK != 0) {
|
|
|
|
pm1 = READ_ACPI_REGISTER(PM1a_CONTROL, 0);
|
|
|
|
}
|
|
if (AcpiInformation->PM1b_CTRL_BLK != 0) {
|
|
|
|
pm1 |= READ_ACPI_REGISTER(PM1b_CONTROL, 0);
|
|
|
|
}
|
|
return (pm1);
|
|
|
|
}
|
|
|
|
USHORT
|
|
READ_PM1_ENABLE(
|
|
VOID
|
|
)
|
|
{
|
|
USHORT pm1=0;
|
|
|
|
if (AcpiInformation->PM1a_BLK != 0) {
|
|
|
|
pm1 = READ_ACPI_REGISTER(PM1a_ENABLE, 0);
|
|
|
|
DebugTraceIO(
|
|
FALSE,
|
|
(PUSHORT)(AcpiInformation->PM1a_BLK+PM1_EN_OFFSET),
|
|
sizeof(USHORT),
|
|
pm1
|
|
);
|
|
|
|
}
|
|
if (AcpiInformation->PM1b_BLK != 0) {
|
|
|
|
pm1 |= READ_ACPI_REGISTER(PM1b_ENABLE, 0);
|
|
|
|
DebugTraceIO(
|
|
FALSE,
|
|
(PUSHORT)(AcpiInformation->PM1b_BLK+PM1_EN_OFFSET),
|
|
sizeof(USHORT),
|
|
pm1
|
|
);
|
|
|
|
}
|
|
return (pm1);
|
|
}
|
|
|
|
USHORT
|
|
READ_PM1_STATUS(
|
|
VOID
|
|
)
|
|
{
|
|
USHORT pm1=0;
|
|
|
|
if (AcpiInformation->PM1a_BLK != 0) {
|
|
|
|
pm1 = READ_ACPI_REGISTER(PM1a_STATUS, 0);
|
|
|
|
DebugTraceIO(
|
|
FALSE,
|
|
(PUSHORT)(AcpiInformation->PM1a_BLK+PM1_STS_OFFSET),
|
|
sizeof(USHORT),
|
|
pm1
|
|
);
|
|
|
|
}
|
|
if (AcpiInformation->PM1b_BLK != 0) {
|
|
|
|
pm1 |= READ_ACPI_REGISTER(PM1b_STATUS, 0);
|
|
|
|
DebugTraceIO(
|
|
FALSE,
|
|
(PUSHORT)(AcpiInformation->PM1b_BLK+PM1_STS_OFFSET),
|
|
sizeof(USHORT),
|
|
pm1
|
|
);
|
|
|
|
}
|
|
return (pm1);
|
|
}
|
|
|
|
VOID
|
|
WRITE_PM1_CONTROL(
|
|
USHORT Value,
|
|
BOOLEAN Destructive,
|
|
ULONG Flags
|
|
)
|
|
{
|
|
|
|
if (!Destructive) {
|
|
|
|
USHORT pm1;
|
|
|
|
if ( (Flags & WRITE_REGISTER_A) && (AcpiInformation->PM1a_BLK != 0) ) {
|
|
|
|
pm1 = READ_ACPI_REGISTER(PM1a_CONTROL, 0);
|
|
pm1 |= Value;
|
|
WRITE_ACPI_REGISTER(PM1a_CONTROL, 0, pm1);
|
|
|
|
}
|
|
if ( (Flags & WRITE_REGISTER_B) && (AcpiInformation->PM1b_BLK != 0) ) {
|
|
|
|
pm1 = READ_ACPI_REGISTER(PM1b_CONTROL, 0);
|
|
pm1 |= Value;
|
|
WRITE_ACPI_REGISTER(PM1b_CONTROL, 0, pm1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// clear this bit and the system dies
|
|
// it is legit when called by the ACPI shutdown code
|
|
// which will use the WRITE_SCI flag.
|
|
//
|
|
ASSERT ( (Flags & WRITE_SCI) || (Value & PM1_SCI_EN) );
|
|
|
|
if ( (Flags & WRITE_REGISTER_A) && (AcpiInformation->PM1a_BLK != 0) ) {
|
|
|
|
WRITE_ACPI_REGISTER(PM1a_CONTROL, 0, Value);
|
|
|
|
}
|
|
if ( (Flags & WRITE_REGISTER_B) && (AcpiInformation->PM1b_BLK != 0) ) {
|
|
|
|
WRITE_ACPI_REGISTER(PM1b_CONTROL, 0, Value);
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
VOID
|
|
WRITE_PM1_ENABLE(
|
|
USHORT Value
|
|
)
|
|
{
|
|
|
|
if (AcpiInformation->PM1a_BLK != 0) {
|
|
|
|
WRITE_ACPI_REGISTER(PM1a_ENABLE, 0, Value);
|
|
|
|
DebugTraceIO(
|
|
TRUE,
|
|
(PUSHORT)(AcpiInformation->PM1a_BLK+PM1_EN_OFFSET),
|
|
sizeof(USHORT),
|
|
Value
|
|
);
|
|
|
|
}
|
|
if (AcpiInformation->PM1b_BLK != 0) {
|
|
|
|
WRITE_ACPI_REGISTER(PM1b_ENABLE, 0, Value);
|
|
|
|
DebugTraceIO(
|
|
TRUE,
|
|
(PUSHORT)(AcpiInformation->PM1b_BLK+PM1_EN_OFFSET),
|
|
sizeof(USHORT),
|
|
Value
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
USHORT
|
|
DefPortReadAcpiRegister(
|
|
ACPI_REG_TYPE AcpiReg,
|
|
ULONG Register
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read from the specified ACPI fixed register.
|
|
|
|
Arguments:
|
|
|
|
AcpiReg - Specifies which ACPI fixed register to read from.
|
|
|
|
Register - Specifies which GP register to read from. Not used for PM1x
|
|
registers.
|
|
|
|
Return Value:
|
|
|
|
Value of the specified ACPI fixed register.
|
|
|
|
--*/
|
|
{
|
|
switch (AcpiReg) {
|
|
|
|
case PM1a_ENABLE:
|
|
return READ_PORT_USHORT((PUSHORT)(AcpiInformation->PM1a_BLK +
|
|
PM1_EN_OFFSET));
|
|
break;
|
|
|
|
case PM1b_ENABLE:
|
|
return READ_PORT_USHORT((PUSHORT)(AcpiInformation->PM1b_BLK +
|
|
PM1_EN_OFFSET));
|
|
break;
|
|
|
|
case PM1a_STATUS:
|
|
return READ_PORT_USHORT((PUSHORT)AcpiInformation->PM1a_BLK +
|
|
PM1_STS_OFFSET);
|
|
break;
|
|
|
|
case PM1b_STATUS:
|
|
return READ_PORT_USHORT((PUSHORT)AcpiInformation->PM1b_BLK +
|
|
PM1_STS_OFFSET);
|
|
break;
|
|
|
|
case PM1a_CONTROL:
|
|
return READ_PORT_USHORT((PUSHORT)AcpiInformation->PM1a_CTRL_BLK);
|
|
break;
|
|
|
|
case PM1b_CONTROL:
|
|
return READ_PORT_USHORT((PUSHORT)AcpiInformation->PM1b_CTRL_BLK);
|
|
break;
|
|
|
|
case GP_STATUS:
|
|
if (Register < AcpiInformation->Gpe0Size) {
|
|
return READ_PORT_UCHAR((PUCHAR)(AcpiInformation->GP0_BLK +
|
|
Register));
|
|
} else {
|
|
return READ_PORT_UCHAR((PUCHAR)(AcpiInformation->GP1_BLK +
|
|
Register -
|
|
AcpiInformation->Gpe0Size));
|
|
}
|
|
break;
|
|
|
|
case GP_ENABLE:
|
|
if (Register < AcpiInformation->Gpe0Size) {
|
|
return READ_PORT_UCHAR((PUCHAR)(AcpiInformation->GP0_ENABLE +
|
|
Register));
|
|
} else {
|
|
return READ_PORT_UCHAR((PUCHAR)(AcpiInformation->GP1_ENABLE +
|
|
Register -
|
|
AcpiInformation->Gpe0Size));
|
|
}
|
|
break;
|
|
|
|
case SMI_CMD:
|
|
return READ_PORT_UCHAR((PUCHAR)AcpiInformation->SMI_CMD);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (USHORT)-1;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
DefPortWriteAcpiRegister(
|
|
ACPI_REG_TYPE AcpiReg,
|
|
ULONG Register,
|
|
USHORT Value
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write to the specified ACPI fixed register.
|
|
|
|
Arguments:
|
|
|
|
AcpiReg - Specifies which ACPI fixed register to write to.
|
|
|
|
Register - Specifies which GP register to write to. Not used for PM1x
|
|
registers.
|
|
|
|
Value - Data to write.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
switch (AcpiReg) {
|
|
|
|
case PM1a_ENABLE:
|
|
WRITE_PORT_USHORT((PUSHORT)(AcpiInformation->PM1a_BLK +
|
|
PM1_EN_OFFSET), Value);
|
|
break;
|
|
|
|
case PM1b_ENABLE:
|
|
WRITE_PORT_USHORT((PUSHORT)(AcpiInformation->PM1b_BLK +
|
|
PM1_EN_OFFSET), Value);
|
|
break;
|
|
|
|
case PM1a_STATUS:
|
|
WRITE_PORT_USHORT((PUSHORT)AcpiInformation->PM1a_BLK +
|
|
PM1_STS_OFFSET, Value);
|
|
break;
|
|
|
|
case PM1b_STATUS:
|
|
WRITE_PORT_USHORT((PUSHORT)AcpiInformation->PM1b_BLK +
|
|
PM1_STS_OFFSET, Value);
|
|
break;
|
|
|
|
case PM1a_CONTROL:
|
|
WRITE_PORT_USHORT((PUSHORT)AcpiInformation->PM1a_CTRL_BLK, Value);
|
|
break;
|
|
|
|
case PM1b_CONTROL:
|
|
WRITE_PORT_USHORT((PUSHORT)AcpiInformation->PM1b_CTRL_BLK, Value);
|
|
break;
|
|
|
|
case GP_STATUS:
|
|
if (Register < AcpiInformation->Gpe0Size) {
|
|
WRITE_PORT_UCHAR((PUCHAR)(AcpiInformation->GP0_BLK + Register),
|
|
(UCHAR)Value);
|
|
} else {
|
|
WRITE_PORT_UCHAR((PUCHAR)(AcpiInformation->GP1_BLK + Register -
|
|
AcpiInformation->Gpe0Size),
|
|
(UCHAR)Value);
|
|
}
|
|
break;
|
|
|
|
case GP_ENABLE:
|
|
if (Register < AcpiInformation->Gpe0Size) {
|
|
WRITE_PORT_UCHAR((PUCHAR)(AcpiInformation->GP0_ENABLE +
|
|
Register),
|
|
(UCHAR)Value);
|
|
} else {
|
|
WRITE_PORT_UCHAR((PUCHAR)(AcpiInformation->GP1_ENABLE +
|
|
Register -
|
|
AcpiInformation->Gpe0Size),
|
|
(UCHAR)Value);
|
|
}
|
|
break;
|
|
|
|
case SMI_CMD:
|
|
WRITE_PORT_UCHAR((PUCHAR)AcpiInformation->SMI_CMD, (UCHAR)Value);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
USHORT
|
|
DefRegisterReadAcpiRegister(
|
|
ACPI_REG_TYPE AcpiReg,
|
|
ULONG Register
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read from the specified ACPI fixed register.
|
|
|
|
Arguments:
|
|
|
|
AcpiReg - Specifies which ACPI fixed register to read from.
|
|
|
|
Register - Specifies which GP register to read from. Not used for PM1x
|
|
registers.
|
|
|
|
Return Value:
|
|
|
|
Value of the specified ACPI fixed register.
|
|
|
|
--*/
|
|
{
|
|
switch (AcpiReg) {
|
|
|
|
case PM1a_ENABLE:
|
|
return READ_REGISTER_USHORT((PUSHORT)(AcpiInformation->PM1a_BLK +
|
|
PM1_EN_OFFSET));
|
|
break;
|
|
|
|
case PM1b_ENABLE:
|
|
return READ_REGISTER_USHORT((PUSHORT)(AcpiInformation->PM1b_BLK +
|
|
PM1_EN_OFFSET));
|
|
break;
|
|
|
|
case PM1a_STATUS:
|
|
return READ_REGISTER_USHORT((PUSHORT)AcpiInformation->PM1a_BLK +
|
|
PM1_STS_OFFSET);
|
|
break;
|
|
|
|
case PM1b_STATUS:
|
|
return READ_REGISTER_USHORT((PUSHORT)AcpiInformation->PM1b_BLK +
|
|
PM1_STS_OFFSET);
|
|
break;
|
|
|
|
case PM1a_CONTROL:
|
|
return READ_REGISTER_USHORT((PUSHORT)AcpiInformation->PM1a_CTRL_BLK);
|
|
break;
|
|
|
|
case PM1b_CONTROL:
|
|
return READ_REGISTER_USHORT((PUSHORT)AcpiInformation->PM1b_CTRL_BLK);
|
|
break;
|
|
|
|
case GP_STATUS:
|
|
if (Register < AcpiInformation->Gpe0Size) {
|
|
return READ_REGISTER_UCHAR((PUCHAR)(AcpiInformation->GP0_BLK +
|
|
Register));
|
|
} else {
|
|
return READ_REGISTER_UCHAR((PUCHAR)(AcpiInformation->GP1_BLK +
|
|
Register -
|
|
AcpiInformation->Gpe0Size));
|
|
}
|
|
break;
|
|
|
|
case GP_ENABLE:
|
|
if (Register < AcpiInformation->Gpe0Size) {
|
|
return READ_REGISTER_UCHAR((PUCHAR)(AcpiInformation->GP0_ENABLE +
|
|
Register));
|
|
} else {
|
|
return READ_REGISTER_UCHAR((PUCHAR)(AcpiInformation->GP1_ENABLE +
|
|
Register -
|
|
AcpiInformation->Gpe0Size));
|
|
}
|
|
break;
|
|
|
|
case SMI_CMD:
|
|
//
|
|
// SMI_CMD is always register based.
|
|
//
|
|
return READ_PORT_UCHAR((PUCHAR)AcpiInformation->SMI_CMD);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (USHORT)-1;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
DefRegisterWriteAcpiRegister(
|
|
ACPI_REG_TYPE AcpiReg,
|
|
ULONG Register,
|
|
USHORT Value
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write to the specified ACPI fixed register.
|
|
|
|
Arguments:
|
|
|
|
AcpiReg - Specifies which ACPI fixed register to write to.
|
|
|
|
Register - Specifies which GP register to write to. Not used for PM1x
|
|
registers.
|
|
|
|
Value - Data to write.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
switch (AcpiReg) {
|
|
|
|
case PM1a_ENABLE:
|
|
WRITE_REGISTER_USHORT((PUSHORT)(AcpiInformation->PM1a_BLK +
|
|
PM1_EN_OFFSET), Value);
|
|
break;
|
|
|
|
case PM1b_ENABLE:
|
|
WRITE_REGISTER_USHORT((PUSHORT)(AcpiInformation->PM1b_BLK +
|
|
PM1_EN_OFFSET), Value);
|
|
break;
|
|
|
|
case PM1a_STATUS:
|
|
WRITE_REGISTER_USHORT((PUSHORT)AcpiInformation->PM1a_BLK +
|
|
PM1_STS_OFFSET, Value);
|
|
break;
|
|
|
|
case PM1b_STATUS:
|
|
WRITE_REGISTER_USHORT((PUSHORT)AcpiInformation->PM1b_BLK +
|
|
PM1_STS_OFFSET, Value);
|
|
break;
|
|
|
|
case PM1a_CONTROL:
|
|
WRITE_REGISTER_USHORT((PUSHORT)AcpiInformation->PM1a_CTRL_BLK, Value);
|
|
break;
|
|
|
|
case PM1b_CONTROL:
|
|
WRITE_REGISTER_USHORT((PUSHORT)AcpiInformation->PM1b_CTRL_BLK, Value);
|
|
break;
|
|
|
|
case GP_STATUS:
|
|
if (Register < AcpiInformation->Gpe0Size) {
|
|
WRITE_REGISTER_UCHAR((PUCHAR)(AcpiInformation->GP0_BLK + Register),
|
|
(UCHAR)Value);
|
|
} else {
|
|
WRITE_REGISTER_UCHAR((PUCHAR)(AcpiInformation->GP1_BLK + Register -
|
|
AcpiInformation->Gpe0Size),
|
|
(UCHAR)Value);
|
|
}
|
|
break;
|
|
|
|
case GP_ENABLE:
|
|
if (Register < AcpiInformation->Gpe0Size) {
|
|
WRITE_REGISTER_UCHAR((PUCHAR)(AcpiInformation->GP0_ENABLE +
|
|
Register),
|
|
(UCHAR)Value);
|
|
} else {
|
|
WRITE_REGISTER_UCHAR((PUCHAR)(AcpiInformation->GP1_ENABLE +
|
|
Register -
|
|
AcpiInformation->Gpe0Size),
|
|
(UCHAR)Value);
|
|
}
|
|
break;
|
|
|
|
case SMI_CMD:
|
|
//
|
|
// SMI_CMD is always register based.
|
|
//
|
|
WRITE_PORT_UCHAR((PUCHAR)AcpiInformation->SMI_CMD, (UCHAR)Value);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// READ/WRITE_ACPI_REGISTER macros are implemented via these
|
|
// function pointers
|
|
//
|
|
PREAD_ACPI_REGISTER AcpiReadRegisterRoutine = DefPortReadAcpiRegister;
|
|
PWRITE_ACPI_REGISTER AcpiWriteRegisterRoutine = DefPortWriteAcpiRegister;
|