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