windows-nt/Source/XPSP1/NT/base/hals/halacpi/cmosopregion.c
2020-09-26 16:20:57 +08:00

1381 lines
36 KiB
C

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
ixcmos.c
Abstract:
Implements CMOS op region interface functionality
Author:
brian guarraci (t-briang) 07-14-2000
Environment:
Kernel mode only.
Revision History:
--*/
#include "halp.h"
#include "acpitabl.h"
#include "exboosts.h"
#include "wchar.h"
#include "xxacpi.h"
#ifdef ACPI_CMOS_ACTIVATE
//
// prototypes for the 2 HalpGet/Set ixcmos.asm functions
//
ULONG
HalpGetCmosData(
IN ULONG SourceLocation,
IN ULONG SourceAddress,
IN PUCHAR DataBuffer,
IN ULONG ByteCount
);
ULONG
HalpSetCmosData(
IN ULONG SourceLocation,
IN ULONG SourceAddress,
IN PUCHAR DataBuffer,
IN ULONG ByteCount
);
ULONG
HalpcGetCmosDataByType(
IN CMOS_DEVICE_TYPE CmosType,
IN ULONG SourceAddress,
IN PUCHAR DataBuffer,
IN ULONG ByteCount
);
ULONG
HalpcSetCmosDataByType(
IN CMOS_DEVICE_TYPE CmosType,
IN ULONG SourceAddress,
IN PUCHAR DataBuffer,
IN ULONG ByteCount
);
ULONG
HalpReadCmosDataByPort(
IN ULONG AddrPort,
IN ULONG DataPort,
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
);
ULONG
HalpWriteCmosDataByPort(
IN ULONG AddrPort,
IN ULONG DataPort,
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
);
ULONG
HalpReadCmosData(
IN ULONG SourceLocation,
IN ULONG SourceAddress,
IN ULONG ReturnBuffer,
IN PUCHAR ByteCount
);
ULONG
HalpWriteCmosData(
IN ULONG SourceLocation,
IN ULONG SourceAddress,
IN ULONG ReturnBuffer,
IN PUCHAR ByteCount
);
ULONG
HalpReadStdCmosData(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
);
ULONG
HalpWriteStdCmosData(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
);
ULONG
HalpReadRtcStdPCAT(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
);
ULONG
HalpWriteRtcStdPCAT(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
);
ULONG
HalpReadRtcIntelPIIX4(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
);
ULONG
HalpWriteRtcIntelPIIX4(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
);
ULONG
HalpReadExtCmosIntelPIIX4(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
);
ULONG
HalpWriteExtCmosIntelPIIX4(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
);
ULONG
HalpReadRtcDal1501(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
);
ULONG
HalpWriteRtcDal1501(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
);
ULONG
HalpReadExtCmosDal1501(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
);
ULONG
HalpWriteExtCmosDal1501(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
);
//
// at the time of this writing, the largest known cmos ram address is 0xff
// that is, for a given cmos ram bank, the largest address is 0xff
//
typedef enum {
LARGEST_KNOWN_CMOS_RAM_ADDRESS = 0xff
} CMOS_RAM_ADDR_LIMITS;
//
// Additional information about Standard CMOS/RTC can be acquired at:
//
// "ISA System Architecture" Mindshare, Inc. (ISBN:0-201-40996-8) Chaper 21.
//
// To put the registers and the RTC region in context, the following
// constants describe the layout of the registers (0x00 - 0x0d).
// Registers A-D are control registers which affect the state of the rtc.
//
typedef enum {
CMOS_RAM_STDPCAT_SECONDS = 0,
CMOS_RAM_STDPCAT_SECONDS_ALARM,
CMOS_RAM_STDPCAT_MINUTES,
CMOS_RAM_STDPCAT_MINUTES_ALARM,
CMOS_RAM_STDPCAT_HOURS,
CMOS_RAM_STDPCAT_HOURS_ALARM,
CMOS_RAM_STDPCAT_DAY_OF_WEEK,
CMOS_RAM_STDPCAT_DATE_OF_MONTH,
CMOS_RAM_STDPCAT_MONTH,
CMOS_RAM_STDPCAT_YEAR,
CMOS_RAM_STDPCAT_REGISTER_A,
CMOS_RAM_STDPCAT_REGISTER_B,
CMOS_RAM_STDPCAT_REGISTER_C,
CMOS_RAM_STDPCAT_REGISTER_D
} CMOS_RAM_STDPCAT_REGISTERS;
//
// definition of bits with in the control registers
//
typedef enum {
//
// (Update In Progress)
// when the rtc is updating the rtc registers, this bit is set
//
//
CMOS_RAM_STDPCAT_REGISTER_A_UIP_BIT = 0x80,
//
// this bit must be set when updating the rtc
//
CMOS_RAM_STDPCAT_REGISTER_B_SET_BIT = 0x80
} CMOS_RAM_STDPCAT_REGISTER_BITS;
//
// Additional information about the Intel PIIX4 cmos/rtc chip
// can be acquired at:
//
// http://developer.intel.com/design/intarch/DATASHTS/29056201.pdf
//
// To put the registers and the RTC region in context, the following
// constants describe the layout of the
//
// Intel PIIX4 CMOS ram
//
// for the 0x00 - 0x0d registers. Registers A-D are control registers
// which affect the state of the rtc.
//
//
//
typedef enum {
CMOS_RAM_PIIX4_SECONDS = 0,
CMOS_RAM_PIIX4_SECONDS_ALARM,
CMOS_RAM_PIIX4_MINUTES,
CMOS_RAM_PIIX4_MINUTES_ALARM,
CMOS_RAM_PIIX4_HOURS,
CMOS_RAM_PIIX4_HOURS_ALARM,
CMOS_RAM_PIIX4_DAY_OF_WEEK,
CMOS_RAM_PIIX4_DATE_OF_MONTH,
CMOS_RAM_PIIX4_MONTH,
CMOS_RAM_PIIX4_YEAR,
CMOS_RAM_PIIX4_REGISTER_A,
CMOS_RAM_PIIX4_REGISTER_B,
CMOS_RAM_PIIX4_REGISTER_C,
CMOS_RAM_PIIX4_REGISTER_D
} CMOS_RAM_PIIX4_REGISTERS;
//
// definition of bits with in the control registers
//
typedef enum {
//
// (Update In Progress)
// when the rtc is updating the rtc registers, this bit is set
//
//
CMOS_RAM_PIIX4_REGISTER_A_UIP_BIT = 0x80,
//
// this bit must be set when updating the rtc
//
CMOS_RAM_PIIX4_REGISTER_B_SET_BIT = 0x80
} CMOS_RAM_PIIX4_REGISTER_BITS;
//
// Additional information about the Dallas 1501 cmos/rtc chip
// can be acquired at:
//
// http://www.dalsemi.com/datasheets/pdfs/1501-11.pdf
//
// To put the registers and the RTC region in context, the following
// constants describe the layout of the
//
// Dallas 1501 CMOS ram
//
// for the 0x00 - 0x0d registers. Registers A-D are control registers
// which affect the state of the rtc.
//
//
//
typedef enum {
CMOS_RAM_DAL1501_SECONDS = 0,
CMOS_RAM_DAL1501_MINUTES,
CMOS_RAM_DAL1501_HOURS,
CMOS_RAM_DAL1501_DAY,
CMOS_RAM_DAL1501_DATE,
CMOS_RAM_DAL1501_MONTH,
CMOS_RAM_DAL1501_YEAR,
CMOS_RAM_DAL1501_CENTURY,
CMOS_RAM_DAL1501_ALARM_SECONDS,
CMOS_RAM_DAL1501_ALARM_MINUTES,
CMOS_RAM_DAL1501_ALARM_HOURS,
CMOS_RAM_DAL1501_ALARM_DAYDATE,
CMOS_RAM_DAL1501_WATCHDOG0,
CMOS_RAM_DAL1501_WATCHDOG1,
CMOS_RAM_DAL1501_REGISTER_A,
CMOS_RAM_DAL1501_REGISTER_B,
CMOS_RAM_DAL1501_RAM_ADDR_LSB, // 0x00 - 0xff
CMOS_RAM_DAL1501_RESERVED0,
CMOS_RAM_DAL1501_RESERVED1,
CMOS_RAM_DAL1501_RAM_DATA // 0x00 - 0xff
} CMOS_RAM_DAL1501_REGISTERS;
typedef enum {
//
// The TE bit controls the update status of the external
// RTC registers. When it is 0, the registers are frozen
// with the last RTC values. If you modifiy the registers
// while TE = 0, then when TE is set, the modifications
// will transfer to the internal registers, hence modifying
// the RTC state. In general, when TE is set, the external
// registers then reflect the current RTC state.
//
CMOS_RAM_DAL1501_REGISTER_B_TE_BIT = 0x80
} CMOS_RAM_DAL1501_REGISTER_BITS;
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
typedef enum {
CmosStdAddrPort = 0x70,
CmosStdDataPort = 0x71
};
typedef enum {
CMOS_READ,
CMOS_WRITE
} CMOS_ACCESS_TYPE;
typedef
ULONG
(*PCMOS_RANGE_HANDLER) (
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
);
typedef struct {
ULONG start;
ULONG stop;
PCMOS_RANGE_HANDLER readHandler;
PCMOS_RANGE_HANDLER writeHandler;
} CMOS_ADDR_RANGE_HANDLER, *PCMOS_ADDR_RANGE_HANDLER;
//
// define the discrete ranges so that the appropriate
// handlers can be used for each.
//
// Note: address ranges are inclusive
//
CMOS_ADDR_RANGE_HANDLER CmosRangeHandlersStdPCAT[] =
{
//
// The RTC region
//
{0, 0x9, HalpReadRtcStdPCAT, HalpWriteRtcStdPCAT},
//
// The standard CMOS RAM region
//
{0x0a, 0x3f, HalpReadStdCmosData, HalpWriteStdCmosData},
//
// end of table
//
{0, 0, 0}
};
CMOS_ADDR_RANGE_HANDLER CmosRangeHandlersIntelPIIX4[] =
{
//
// The RTC region
//
{0, 0x9, HalpReadRtcIntelPIIX4, HalpWriteRtcIntelPIIX4},
//
// The standard CMOS RAM region
//
{0x0a, 0x7f, HalpReadStdCmosData, HalpWriteStdCmosData},
//
// The extended CMOS SRAM region
//
{0x80, 0xff, HalpReadExtCmosIntelPIIX4, HalpWriteExtCmosIntelPIIX4},
//
// end of table
//
{0, 0, 0}
};
CMOS_ADDR_RANGE_HANDLER CmosRangeHandlersDal1501[] =
{
//
// The RTC region
//
{0, 0x0b, HalpReadRtcDal1501, HalpWriteRtcDal1501},
//
// The standard CMOS RAM region
//
{0x0c, 0x0f, HalpReadStdCmosData, HalpWriteStdCmosData},
//
// NOTE: this table skips the standard CMOS range: 0x10 - 0x1f
// because this area is reserved in the spec, and the is no
// apparent reason why the op region should access this area.
// Also, regs 0x10 and 0x13 are used to access the extended
// ram, hence there is no reason why the op region should access
// this either. Hence, all op region access beyond 0x0f are
// interpretted as accesses into the Extended CMOS
//
//
// The extended CMOS SRAM region
//
{0x10, 0x10f, HalpReadExtCmosDal1501, HalpWriteExtCmosDal1501},
//
// end of table
//
{0, 0, 0}
};
ULONG
HalpCmosRangeHandler(
IN CMOS_ACCESS_TYPE AccessType,
IN CMOS_DEVICE_TYPE CmosType,
IN ULONG Address,
IN PUCHAR DataBuffer,
IN ULONG ByteCount
)
{
ULONG bytes; // bytes read in last operation
ULONG offset; // the offset beyond the initial address
ULONG bufOffset; // the index into the data buffer as we read in data
ULONG extAddr; // the corrected address for accessing extended SRAM
ULONG range; // the current address range we are checking for
ULONG bytesRead; // total bytes successfully read
ULONG length; // the length of the current operation read
PCMOS_ADDR_RANGE_HANDLER rangeHandlers; // the table we are using
//
// get the appropriate table
//
switch (CmosType) {
case CmosTypeStdPCAT:
rangeHandlers = CmosRangeHandlersStdPCAT;
break;
case CmosTypeIntelPIIX4:
rangeHandlers = CmosRangeHandlersIntelPIIX4;
break;
case CmosTypeDal1501:
rangeHandlers = CmosRangeHandlersDal1501;
break;
default:
break;
}
bytesRead = 0;
bufOffset = 0;
range = 0;
offset = Address;
length = ByteCount;
while (rangeHandlers[range].stop) {
if (offset <= rangeHandlers[range].stop) {
//
// get the # of bytes to read in this region
//
// length = MIN(remaining # bytes remaining to read, # bytes to read in the current range)
//
length = MIN((ByteCount - bytesRead), (rangeHandlers[range].stop - offset + 1));
//
// Since the handler routines are only called from here, we can consolidate
// the ASSERTIONS. This is also nice, because we know which range in the
// table we are dealing with, hence we know what the limits should be.
//
// make sure both the offset into the range,
// and the operation's length are in bounds
//
ASSERT(offset <= rangeHandlers[range].stop);
ASSERT((offset + length) <= (rangeHandlers[range].stop + 1));
switch (AccessType) {
case CMOS_READ:
bytes = (rangeHandlers[range].readHandler)(
offset,
&DataBuffer[bufOffset],
length);
break;
case CMOS_WRITE:
bytes = (rangeHandlers[range].writeHandler)(
offset,
&DataBuffer[bufOffset],
length);
break;
default:
break;
}
ASSERT(bytes == length);
bytesRead += bytes;
//
// adjust offset based on the length of the last operation
//
offset += length;
bufOffset += length;
}
//
// if offset is at or beyond specified range, then we are done
//
if (offset >= (Address + ByteCount)) {
break;
}
//
// move to the next range
//
range++;
}
ASSERT(bytesRead == ByteCount);
return bytesRead;
}
ULONG
HalpcGetCmosDataByType(
IN CMOS_DEVICE_TYPE CmosType,
IN ULONG Address,
IN PUCHAR DataBuffer,
IN ULONG ByteCount
)
{
return HalpCmosRangeHandler(
CMOS_READ,
CmosType,
Address,
DataBuffer,
ByteCount
);
}
ULONG
HalpcSetCmosDataByType(
IN CMOS_DEVICE_TYPE CmosType,
IN ULONG Address,
IN PUCHAR DataBuffer,
IN ULONG ByteCount
)
{
return HalpCmosRangeHandler(
CMOS_WRITE,
CmosType,
Address,
DataBuffer,
ByteCount
);
}
ULONG
HalpReadCmosDataByPort(
IN ULONG AddrPort,
IN ULONG DataPort,
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
)
/*++
This routine reads the requested number of bytes from CMOS using the
specified ports and stores the data read into the supplied buffer in
system memory. If the requested data amount exceeds the allowable
extent of the source location, the return data is truncated.
Arguments:
AddrPort : address in the ISA I/O space to put the address
DataPort : address in the ISA I/O space to put the data
SourceAddress : address in CMOS where data is to be read from
ReturnBuffer : address in system memory for return data
ByteCount : number of bytes to be read
Returns:
Number of bytes actually read.
Note:
This routine doesn't perform safety precautions when operating
in the RTC region of the CMOS. Use the appropriate RTC routine
instead.
--*/
{
ULONG offset;
ULONG bufOffset;
ULONG upperAddrBound;
upperAddrBound = SourceAddress + ByteCount;
ASSERT(SourceAddress <= LARGEST_KNOWN_CMOS_RAM_ADDRESS);
ASSERT(upperAddrBound <= (LARGEST_KNOWN_CMOS_RAM_ADDRESS + 1));
//
// NOTE: The spinlock is needed even in the UP case, because
// the resource is also used in an interrupt handler (profiler).
// If we own the spinlock in this routine, and we service
// the profiler interrupt (which will wait for the spinlock forever),
// then we have a hosed system.
//
HalpAcquireCmosSpinLock();
for (offset = SourceAddress, bufOffset = 0; offset < upperAddrBound; offset++, bufOffset++) {
WRITE_PORT_UCHAR((PUCHAR)AddrPort, (UCHAR)offset);
ReturnBuffer[bufOffset] = READ_PORT_UCHAR((PUCHAR)DataPort);
}
HalpReleaseCmosSpinLock();
return bufOffset;
}
ULONG
HalpWriteCmosDataByPort(
IN ULONG AddrPort,
IN ULONG DataPort,
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
)
/*++
This routine reads the requested number of bytes from CMOS using the
specified ports and stores the data read into the supplied buffer in
system memory. If the requested data amount exceeds the allowable
extent of the source location, the return data is truncated.
Arguments:
AddrPort : address in the ISA I/O space to put the address
DataPort : address in the ISA I/O space to put the data
SourceAddress : address in CMOS where data is to be read from
ReturnBuffer : address in system memory for return data
ByteCount : number of bytes to be read
Returns:
Number of bytes actually read.
Note:
This routine doesn't perform safety precautions when operating
in the RTC region of the CMOS. Use the appropriate RTC routine
instead.
--*/
{
ULONG offset;
ULONG bufOffset;
ULONG upperAddrBound;
upperAddrBound = SourceAddress + ByteCount;
ASSERT(SourceAddress <= LARGEST_KNOWN_CMOS_RAM_ADDRESS);
ASSERT(upperAddrBound <= (LARGEST_KNOWN_CMOS_RAM_ADDRESS + 1));
//
// NOTE: The spinlock is needed even in the UP case, because
// the resource is also used in an interrupt handler (profiler).
// If we own the spinlock in this routine, and we service
// the profiler interrupt (which will wait for the spinlock forever),
// then we have a hosed system.
//
HalpAcquireCmosSpinLock();
for (offset = SourceAddress, bufOffset = 0; offset < upperAddrBound; offset++, bufOffset++) {
WRITE_PORT_UCHAR((PUCHAR)AddrPort, (UCHAR)offset);
WRITE_PORT_UCHAR((PUCHAR)DataPort, (UCHAR)(ReturnBuffer[bufOffset]));
}
HalpReleaseCmosSpinLock();
return bufOffset;
}
ULONG
HalpReadStdCmosData(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
)
{
return HalpReadCmosDataByPort(
CmosStdAddrPort,
CmosStdDataPort,
SourceAddress,
ReturnBuffer,
ByteCount
);
}
ULONG
HalpWriteStdCmosData(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
)
{
return HalpWriteCmosDataByPort(
CmosStdAddrPort,
CmosStdDataPort,
SourceAddress,
ReturnBuffer,
ByteCount
);
}
ULONG
HalpReadRtcStdPCAT(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
)
/*++
This routine handles reads into the standard PC/AT RTC range.
Arguments:
SourceAddress : address in CMOS where data is to be read from
ReturnBuffer : address in system memory for return data
ByteCount : number of bytes to be read
Returns:
Number of bytes actually read.
--*/
{
ULONG offset;
ULONG bufOffset;
ULONG status; // register status
ULONG uip; // update in progress bit
ULONG upperAddrBound;
upperAddrBound = SourceAddress + ByteCount;
//
// NOTE: The spinlock is needed even in the UP case, because
// the resource is also used in an interrupt handler (profiler).
// If we own the spinlock in this routine, and we service
// the profiler interrupt (which will wait for the spinlock forever),
// then we have a hosed system.
//
HalpAcquireCmosSpinLock();
//
// According to "ISA System Architecture"
// by Mindshare, Inc. (ISBN:0-201-40996-8) Chaper 21.
// the access method for reading standard PC/AT RTC is:
//
// 1. wait for the Update In Progress bit to clear
// this is bit 7 of register A
//
// 2. read
//
//
// wait until the rtc is done updating
//
do {
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_STDPCAT_REGISTER_A);
status = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
uip = status & CMOS_RAM_STDPCAT_REGISTER_A_UIP_BIT;
} while (uip);
//
// read
//
for (offset = SourceAddress, bufOffset = 0; offset < upperAddrBound; offset++, bufOffset++) {
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, (UCHAR)offset);
ReturnBuffer[bufOffset] = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
}
HalpReleaseCmosSpinLock();
return bufOffset;
}
ULONG
HalpWriteRtcStdPCAT(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
)
/*++
This routine handles writes into the standard PC/AT RTC range.
Arguments:
SourceAddress : address in CMOS where data is to be read from
ReturnBuffer : address in system memory for return data
ByteCount : number of bytes to be read
Returns:
Number of bytes actually read.
--*/
{
ULONG offset;
ULONG bufOffset;
ULONG status; // register status
ULONG uip; // update in progress bit
ULONG upperAddrBound;
upperAddrBound = SourceAddress + ByteCount;
//
// NOTE: The spinlock is needed even in the UP case, because
// the resource is also used in an interrupt handler (profiler).
// If we own the spinlock in this routine, and we service
// the profiler interrupt (which will wait for the spinlock forever),
// then we have a hosed system.
//
HalpAcquireCmosSpinLock();
//
// According to "ISA System Architecture"
// by Mindshare, Inc. (ISBN:0-201-40996-8) Chapter 21.
// the access method for writing to standard PC/AT RTC is:
//
// 1. wait for the Update In Progress bit (UIP) to clear,
// where UIP is bit 7 of register A
//
// 2. set the SET bit to notify the RTC that the registers
// are being updated. The SET bit is bit 7 of register B
//
// 3. update the rtc registers
//
// 4. clear the SET bit, notifying the RTC that we are done writing
//
//
// wait until the rtc is done updating
//
do {
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_STDPCAT_REGISTER_A);
status = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
uip = status & CMOS_RAM_STDPCAT_REGISTER_A_UIP_BIT;
} while (uip);
//
// set the SET bit of register B
//
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_STDPCAT_REGISTER_B);
status = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
status |= CMOS_RAM_STDPCAT_REGISTER_B_SET_BIT;
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_STDPCAT_REGISTER_B);
WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)(status));
//
// update the rtc registers
//
for (offset = SourceAddress, bufOffset = 0; offset < upperAddrBound; offset++, bufOffset++) {
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, (UCHAR)offset);
WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)(ReturnBuffer[bufOffset]));
}
//
// clear the SET bit of register B
//
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_STDPCAT_REGISTER_B);
status = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
status &= ~CMOS_RAM_STDPCAT_REGISTER_B_SET_BIT;
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_STDPCAT_REGISTER_B);
WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)(status));
HalpReleaseCmosSpinLock();
return bufOffset;
}
ULONG
HalpReadRtcIntelPIIX4(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
)
/*++
This routine reads the RTC range for the Intel PIIX4 CMOS/RTC chip
Arguments:
SourceAddress : address in CMOS where data is to be read from
ReturnBuffer : address in system memory for return data
ByteCount : number of bytes to be read
Returns:
Number of bytes actually read.
--*/
{
//
// Use the access method for the Standard PC/AT since it is
// equivalent to the Intel PIIX4 access method.
//
return HalpReadRtcStdPCAT(
SourceAddress,
ReturnBuffer,
ByteCount
);
}
ULONG
HalpWriteRtcIntelPIIX4(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
)
/*++
This routine handles writes into the RTC range for the Intel PIIX4 CMOS/RTC chip
Arguments:
SourceAddress : address in CMOS where data is to be read from
ReturnBuffer : address in system memory for return data
ByteCount : number of bytes to be read
Returns:
Number of bytes actually read.
--*/
{
//
// Use the access method for the Standard PC/AT since it is
// equivalent to the Intel PIIX4 access method.
//
return HalpWriteRtcStdPCAT(
SourceAddress,
ReturnBuffer,
ByteCount
);
}
ULONG
HalpReadExtCmosIntelPIIX4(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
)
/*++
This routine reads the RTC registers for the Intel PIIX4 CMOS/RTC chip.
Arguments:
SourceAddress : address in CMOS where data is to be read from
ReturnBuffer : address in system memory for return data
ByteCount : number of bytes to be read
Returns:
Number of bytes actually read.
--*/
{
//
// The Intel PIIX4 Extended SRAM is accessed using
// next pair of IO ports above the standard addr/data ports.
// Hence, we can simply forward the request with the correct pair.
//
return HalpReadCmosDataByPort(
CmosStdAddrPort + 2,
CmosStdDataPort + 2,
SourceAddress,
ReturnBuffer,
ByteCount
);
}
ULONG
HalpWriteExtCmosIntelPIIX4(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
)
/*++
This routine handles writes into the RTC registers for the Intel PIIX4 CMOS/RTC chip.
Arguments:
SourceAddress : address in CMOS where data is to be read from
ReturnBuffer : address in system memory for return data
ByteCount : number of bytes to be read
Returns:
Number of bytes actually read.
--*/
{
//
// The Intel PIIX4 Extended SRAM is accessed using
// next pair of IO ports above the standard addr/data ports.
// Hence, we can simply forward the request with the correct pair.
//
return HalpWriteCmosDataByPort(
CmosStdAddrPort + 2,
CmosStdDataPort + 2,
SourceAddress,
ReturnBuffer,
ByteCount
);
}
ULONG
HalpReadRtcDal1501(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
)
/*++
This routine reads the RTC registers for the Dallas 1501 CMOS/RTC chip.
Arguments:
SourceAddress : address in CMOS where data is to be read from
ReturnBuffer : address in system memory for return data
ByteCount : number of bytes to be read
Returns:
Number of bytes actually read.
--*/
{
ULONG offset;
ULONG bufOffset;
ULONG status; // register status
ULONG upperAddrBound;
upperAddrBound = SourceAddress + ByteCount;
//
// NOTE: The spinlock is needed even in the UP case, because
// the resource is also used in an interrupt handler (profiler).
// If we own the spinlock in this routine, and we service
// the profiler interrupt (which will wait for the spinlock forever),
// then we have a hosed system.
//
HalpAcquireCmosSpinLock();
//
// NOTE: The recommended procedure for reading the Dallas 1501 RTC is to stop
// external register updates while reading. Internally, updates in the RTC
// continue as normal. This procedure prevents reading the registers while
// they are in transition
//
//
// Clear the TE bit of register B to stop external updates
//
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_REGISTER_B);
status = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
status &= ~CMOS_RAM_DAL1501_REGISTER_B_TE_BIT;
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_REGISTER_B);
WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)status);
for (offset = SourceAddress, bufOffset = 0; offset < upperAddrBound; offset++, bufOffset++) {
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, (UCHAR)offset);
ReturnBuffer[bufOffset] = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
}
//
// Set the TE bit of register B to enable external updates
//
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_REGISTER_B);
status = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
status |= CMOS_RAM_DAL1501_REGISTER_B_TE_BIT;
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_REGISTER_B);
WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)status);
HalpReleaseCmosSpinLock();
return bufOffset;
}
ULONG
HalpWriteRtcDal1501(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
)
/*++
This routine handles writes into the RTC region for the Dallas 1501 CMOS/RTC chip.
Arguments:
SourceAddress : address in CMOS where data is to be read from
ReturnBuffer : address in system memory for return data
ByteCount : number of bytes to be read
Returns:
Number of bytes actually read.
--*/
{
ULONG offset;
ULONG bufOffset;
ULONG status; // register status
ULONG upperAddrBound;
upperAddrBound = SourceAddress + ByteCount;
//
// NOTE: The spinlock is needed even in the UP case, because
// the resource is also used in an interrupt handler (profiler).
// If we own the spinlock in this routine, and we service
// the profiler interrupt (which will wait for the spinlock forever),
// then we have a hosed system.
//
HalpAcquireCmosSpinLock();
//
// NOTE: The recommended procedure for writing the Dallas 1501 RTC is to stop
// external register updates while writing. The modified register values
// are transferred into the internal registers when the TE bit is set. Operation
// then continues normally.
//
//
// Clear the TE bit of register B to stop external updates
//
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_REGISTER_B);
status = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
status &= ~CMOS_RAM_DAL1501_REGISTER_B_TE_BIT;
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_REGISTER_B);
WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)status);
for (offset = SourceAddress, bufOffset = 0; offset < upperAddrBound; offset++, bufOffset++) {
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, (UCHAR)offset);
WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)(ReturnBuffer[bufOffset]));
}
//
// Set the TE bit of register B to enable external updates
//
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_REGISTER_B);
status = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
status |= CMOS_RAM_DAL1501_REGISTER_B_TE_BIT;
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_REGISTER_B);
WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)status);
HalpReleaseCmosSpinLock();
return bufOffset;
}
ULONG
HalpReadExtCmosDal1501(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
)
{
ULONG offset;
ULONG bufOffset;
ULONG status; // register status
ULONG upperAddrBound;
upperAddrBound = SourceAddress + ByteCount;
//
// NOTE: The spinlock is needed even in the UP case, because
// the resource is also used in an interrupt handler (profiler).
// If we own the spinlock in this routine, and we service
// the profiler interrupt (which will wait for the spinlock forever),
// then we have a hosed system.
//
HalpAcquireCmosSpinLock();
//
// reading from Dallas 1501 SRAM is a 2 step process:
// 1. First, we write the address to the RAM_ADDR_LSB register in the standard CMOS region.
// 2. Then we read the data byte from the RAM_DATA register in the standard CMOS region.
//
for (offset = SourceAddress, bufOffset = 0; offset < upperAddrBound; offset++, bufOffset++) {
//
// specify the offset into SRAM
//
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_RAM_ADDR_LSB);
WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)offset);
//
// read the data from SRAM[offset]
//
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_RAM_DATA);
ReturnBuffer[bufOffset] = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
}
HalpReleaseCmosSpinLock();
return bufOffset;
}
ULONG
HalpWriteExtCmosDal1501(
IN ULONG SourceAddress,
IN PUCHAR ReturnBuffer,
IN ULONG ByteCount
)
{
ULONG offset;
ULONG bufOffset;
ULONG status; // register status
ULONG upperAddrBound;
upperAddrBound = SourceAddress + ByteCount;
//
// NOTE: The spinlock is needed even in the UP case, because
// the resource is also used in an interrupt handler (profiler).
// If we own the spinlock in this routine, and we service
// the profiler interrupt (which will wait for the spinlock forever),
// then we have a hosed system.
//
HalpAcquireCmosSpinLock();
//
// writing to Dallas 1501 SRAM is a 2 step process:
// 1. First, we write the address to the RAM_ADDR_LSB register in the standard CMOS region.
// 2. Then we write the data byte to the RAM_DATA register in the standard CMOS region.
//
for (offset = SourceAddress, bufOffset = 0; offset < upperAddrBound; offset++, bufOffset++) {
//
// specify the offset into SRAM
//
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_RAM_ADDR_LSB);
WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)offset);
//
// specify the data to be written into SRAM[offset]
//
WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_RAM_DATA);
WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)(ReturnBuffer[bufOffset]));
}
HalpReleaseCmosSpinLock();
return bufOffset;
}
#endif // ACPI_CMOS_ACTIVATE