679 lines
14 KiB
C
679 lines
14 KiB
C
/*++
|
|
|
|
Copyright (c) 1993 NCR Corporation
|
|
|
|
Module Name:
|
|
|
|
ncrsus.c
|
|
|
|
Abstract:
|
|
|
|
Provides the interface to the NCR SUS.
|
|
|
|
Author:
|
|
|
|
Rick Ulmer (rick.ulmer@columbiasc.ncr.com) 8-Sep-1993
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
#include "ncr.h"
|
|
#include "ncrcat.h"
|
|
#include "ncrsus.h"
|
|
#include "ncrarb.h"
|
|
|
|
|
|
PNST_SUS_LOG SUSErrorLogHeader;
|
|
PUCHAR SUSErrorLogData;
|
|
PUCHAR CurrentSUSErrorEntryPosition;
|
|
USHORT CurrentSUSErrorEntryBytesRemaining;
|
|
|
|
|
|
PKERNEL_SUS_MAILBOX SUSMailbox;
|
|
PPROCESSOR_BOARD_INFO SUSBoardInfo;
|
|
PCPU_INFO SUSCpuInfo;
|
|
|
|
extern ULONG NCRExistingProcessorMask;
|
|
extern ULONG NCRExistingDyadicProcessorMask;
|
|
extern ULONG NCRExistingQuadProcessorMask;
|
|
|
|
ULONG HalpGetCmosData (ULONG SourceLocation, ULONG SourceAddress,
|
|
PUCHAR Buffer, ULONG Length);
|
|
|
|
ULONG HalpSetCmosData (ULONG SourceLocation, ULONG SourceAddress,
|
|
PUCHAR Buffer, ULONG Length);
|
|
|
|
|
|
BOOLEAN HalpCheckSUSLogSanity();
|
|
|
|
VOID HalpWriteCheckSum(
|
|
PUCHAR CheckSumStart,
|
|
PUCHAR CheckSumEnd,
|
|
PUCHAR CheckSumLowByte,
|
|
PUCHAR CheckSumHighByte
|
|
);
|
|
|
|
ULONG NCRTranslateCMOSMask(ULONG);
|
|
|
|
|
|
|
|
VOID
|
|
HalpInitializeSUSInterface (
|
|
)
|
|
|
|
{
|
|
PHYSICAL_ADDRESS physical_log_address;
|
|
ULONG LowPart;
|
|
UCHAR data;
|
|
ULONG i;
|
|
|
|
|
|
//
|
|
// Get pointers to SUS Error Log
|
|
//
|
|
|
|
SUSErrorLogHeader = NULL;
|
|
SUSErrorLogData = NULL;
|
|
|
|
LowPart = 0;
|
|
|
|
HalpGetCmosData(1,SUS_LOG_PTR,
|
|
(PUCHAR)&LowPart,NST_LOG_PTR_SIZE);
|
|
|
|
SUSErrorLogHeader = (PNST_SUS_LOG)HalpMapPhysicalMemory(LowPart,
|
|
COMPUTE_PAGES_SPANNED(LowPart,sizeof(NST_SUS_LOG)));
|
|
|
|
|
|
if (SUSErrorLogHeader != NULL) {
|
|
|
|
LowPart += SUSErrorLogHeader->PhysicalLogBegin;
|
|
|
|
SUSErrorLogData = (PUCHAR)HalpMapPhysicalMemory(LowPart,
|
|
COMPUTE_PAGES_SPANNED(LowPart,SUSErrorLogHeader->PhysicalLogEnd));
|
|
|
|
|
|
if (SUSErrorLogData == NULL) {
|
|
// MmUnmapIoSpace(SUSErrorLogHeader,sizeof(NST_SUS_LOG));
|
|
SUSErrorLogHeader = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Make sure SUS error log is OK
|
|
//
|
|
/*RMU
|
|
This is just during debug.......
|
|
|
|
if (SUSErrorLogHeader) {
|
|
SUSErrorLogHeader->FirstUnreadRecord = SUSErrorLogHeader->FirstValidRecord;
|
|
SUSErrorLogHeader->UnreadBytesInLog = SUSErrorLogHeader->ValidBytesInLog;
|
|
}
|
|
*/
|
|
|
|
|
|
if (!HalpCheckSUSLogSanity()) {
|
|
DBGMSG(("SUS Error log is corrputed......................\n"));
|
|
SUSErrorLogHeader = NULL;
|
|
SUSErrorLogData = NULL;
|
|
}
|
|
|
|
|
|
|
|
/*RMU debug phase */
|
|
|
|
//
|
|
// Get Pointer to SUS/Kernel mailbox
|
|
//
|
|
|
|
|
|
LowPart = 0;
|
|
|
|
HalpGetCmosData(1,SUS_MAILBOX_PTR,
|
|
(PUCHAR)&LowPart,4);
|
|
|
|
SUSMailbox = (PKERNEL_SUS_MAILBOX)HalpMapPhysicalMemory(LowPart,
|
|
COMPUTE_PAGES_SPANNED(LowPart,sizeof(KERNEL_SUS_MAILBOX)));
|
|
|
|
SUSMailbox->OSMailboxVersion = FIRST_PASS_INTERFACE;
|
|
SUSMailbox->OSFlags = OS_KNOWS_SYSINT;
|
|
|
|
|
|
//
|
|
// Get Pointer to the SUS board info struct.
|
|
//
|
|
|
|
LowPart = (ULONG)SUSMailbox->BoardData;
|
|
|
|
SUSBoardInfo = (PPROCESSOR_BOARD_INFO)HalpMapPhysicalMemory(LowPart,
|
|
COMPUTE_PAGES_SPANNED(LowPart,sizeof(PROCESSOR_BOARD_INFO)));
|
|
|
|
DBGMSG(("HalpInitializeSUSInterface: SUSMailbox = 0x%x\n", SUSMailbox));
|
|
DBGMSG(("HalpInitializeSUSInterface: SUSBoardInfo = 0x%x\n", SUSBoardInfo));
|
|
|
|
|
|
//
|
|
// Get Pointer to the SUS cpu info struct.
|
|
//
|
|
|
|
LowPart = (ULONG)SUSMailbox->Cpu_Data;
|
|
|
|
SUSCpuInfo = (PCPU_INFO)HalpMapPhysicalMemory(LowPart,
|
|
COMPUTE_PAGES_SPANNED(LowPart,sizeof(CPU_INFO)));
|
|
|
|
DBGMSG(("HalpInitializeSUSInterface: SUSCpuInfo = 0x%x\n", SUSCpuInfo));
|
|
|
|
|
|
//
|
|
// Now lets go look for all the processor in the system and fill in
|
|
// NCRExistingDyadicProcessorMask and NCRExistingQuadProcessorMask
|
|
//
|
|
|
|
|
|
for (i = 0; i < SUSCpuInfo->NumberOfCpus; i++ ) {
|
|
|
|
data = SUSCpuInfo->CpuData[i].CPU_HardwareId;
|
|
|
|
if ((data & 0xc0) == 0xc0) {
|
|
|
|
//
|
|
// this is a Quad processor
|
|
//
|
|
// convert the who_am_i into the proper mask
|
|
//
|
|
// format:
|
|
//
|
|
// 1100ccss
|
|
//
|
|
// cc = processor bits
|
|
// ss = slot bits
|
|
//
|
|
|
|
NCRExistingQuadProcessorMask |= (1<<((data & 0xf)>>2))<<(((data&3)<<2));
|
|
|
|
} else {
|
|
|
|
//
|
|
// this is a Dyadic processor
|
|
//
|
|
|
|
NCRExistingDyadicProcessorMask |= NCRTranslateCMOSMask(data);
|
|
}
|
|
}
|
|
|
|
|
|
DBGMSG(("HalpInitializeSUSInterface: Dyadic Mask = 0x%x, Quad Mask = 0x%x\n",
|
|
NCRExistingDyadicProcessorMask, NCRExistingQuadProcessorMask));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// Set firmware to perform a cold reset and not take a dump.
|
|
//
|
|
|
|
HalpGetCmosData(1,SUS_RESET_PTR,
|
|
(PUCHAR)&data,1);
|
|
|
|
data |= 0x01;
|
|
|
|
HalpSetCmosData(1,SUS_RESET_PTR,
|
|
(PUCHAR)&data,1);
|
|
|
|
HalpWriteCheckSum((PUCHAR)SUS_HIGH_AVAIL_XSUM_START,
|
|
(PUCHAR)SUS_HIGH_AVAIL_XSUM_END,
|
|
(PUCHAR)SUS_HIGH_AVAIL_XSUM_LOW,
|
|
(PUCHAR)SUS_HIGH_AVAIL_XSUM_HIGH);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
HalpSUSLogError (
|
|
|
|
)
|
|
|
|
{
|
|
//
|
|
// This routine tells SUS to go do FRU analysis. After the FRU
|
|
// analysis the system will reboot
|
|
//
|
|
|
|
DBGMSG(("HalpSUSLogError has been called......\n"));
|
|
|
|
SUSMailbox->OSFlags |= OS_IN_PROGRESS;
|
|
SUSMailbox->MailboxOS = SYSINT_HANDSHAKE;
|
|
|
|
|
|
//
|
|
// Send interrupt from SP to DP
|
|
//
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR)0xf820,(UCHAR)0x11);
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
HalpSUSSwNmi (
|
|
|
|
)
|
|
|
|
{
|
|
|
|
DBGMSG(("HalpSUSSwNmi has been called......\n"));
|
|
|
|
if (SUSMailbox->MailboxSUS == DUMP_BUTTON_INTERRUPT) {
|
|
|
|
SUSMailbox->MailboxOS = NO_COMMAND;
|
|
SUSMailbox->OSFlags |= OS_IN_PROGRESS;
|
|
KeStallExecutionProcessor(1000000); // give DP a chance 1 sec
|
|
|
|
SUSMailbox->MailboxOS = IGNORE_DUMP_BUTTON;
|
|
SUSMailbox->OSFlags &= ~OS_IN_PROGRESS;
|
|
|
|
while (SUSMailbox->MailboxSUS == DUMP_BUTTON_INTERRUPT) {
|
|
KeStallExecutionProcessor(1);
|
|
};
|
|
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
HalpCheckSUSLogSanity (
|
|
)
|
|
|
|
|
|
{
|
|
USHORT bytes_in_log;
|
|
PSUS_ERROR_RECORD_HEADER SUS_header;
|
|
|
|
PUCHAR next_write_record;
|
|
PUCHAR logical_log_end;
|
|
|
|
if (SUSErrorLogHeader == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
next_write_record = ADDRESS_OF(NEXT_WRITE_RECORD);
|
|
logical_log_end = ADDRESS_OF(LOGICAL_LOG_END);
|
|
|
|
if( (FIRST_VALID_RECORD >= PHYS_LOG_END) ||
|
|
(FIRST_UNREAD_RECORD > PHYS_LOG_END) ||
|
|
(LOGICAL_LOG_END > PHYS_LOG_END) ||
|
|
(NEXT_WRITE_RECORD > PHYS_LOG_END) ||
|
|
(VALID_BYTES_IN_LOG > PHYS_LOG_END) ||
|
|
(UNREAD_BYTES_IN_LOG > PHYS_LOG_END) ||
|
|
(UNREAD_BYTES_IN_LOG > VALID_BYTES_IN_LOG) ||
|
|
(VALID_BYTES_IN_LOG > LOGICAL_LOG_END) ) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (VALID_BYTES_IN_LOG == 0)
|
|
return TRUE;
|
|
|
|
|
|
//
|
|
// Make sure the VALID_BYTES_IN_LOG is correct and that the log can be
|
|
// traversed starting with the FIRST_VALID_RECORD.
|
|
//
|
|
|
|
for (bytes_in_log = 0,
|
|
SUS_header = (PSUS_ERROR_RECORD_HEADER)ADDRESS_OF(FIRST_VALID_RECORD);
|
|
bytes_in_log < VALID_BYTES_IN_LOG; ) {
|
|
|
|
|
|
if (SUS_header > (PSUS_ERROR_RECORD_HEADER)logical_log_end)
|
|
return FALSE;
|
|
|
|
if ((SUS_header == (PSUS_ERROR_RECORD_HEADER)logical_log_end))
|
|
SUS_header = (PSUS_ERROR_RECORD_HEADER)SUSErrorLogData;
|
|
|
|
if (SUS_header->RecordLength <= 0)
|
|
return FALSE;
|
|
|
|
if ((bytes_in_log += SUS_header->RecordLength) > VALID_BYTES_IN_LOG)
|
|
return FALSE;
|
|
|
|
SUS_header = (PSUS_ERROR_RECORD_HEADER)((ULONG)SUS_header +
|
|
(ULONG)SUS_header->RecordLength);
|
|
}
|
|
|
|
if( bytes_in_log != VALID_BYTES_IN_LOG )
|
|
return FALSE;
|
|
|
|
|
|
if (UNREAD_BYTES_IN_LOG == 0)
|
|
return TRUE;
|
|
|
|
//
|
|
// Make sure the UNREAD_BYTES_IN_LOG is correct and that the log can be
|
|
// traversed starting with the FIRST_UNREAD_RECORD.
|
|
//
|
|
for (bytes_in_log = 0,
|
|
SUS_header = (PSUS_ERROR_RECORD_HEADER)ADDRESS_OF(FIRST_UNREAD_RECORD);
|
|
bytes_in_log < UNREAD_BYTES_IN_LOG; ) {
|
|
|
|
if (SUS_header > (PSUS_ERROR_RECORD_HEADER)logical_log_end)
|
|
return FALSE;
|
|
|
|
if ((SUS_header == (PSUS_ERROR_RECORD_HEADER)logical_log_end))
|
|
SUS_header = (PSUS_ERROR_RECORD_HEADER)SUSErrorLogData;
|
|
|
|
if (SUS_header->RecordLength <= 0)
|
|
return FALSE;
|
|
|
|
if ((bytes_in_log += SUS_header->RecordLength) > UNREAD_BYTES_IN_LOG)
|
|
return FALSE;
|
|
|
|
SUS_header = (PSUS_ERROR_RECORD_HEADER)((ULONG)SUS_header +
|
|
(ULONG)SUS_header->RecordLength);
|
|
}
|
|
|
|
if( bytes_in_log != UNREAD_BYTES_IN_LOG )
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LONG
|
|
HalGetSUSErrorLogEntry (
|
|
PUCHAR ErrorEntry
|
|
)
|
|
|
|
{
|
|
PSUS_ERROR_RECORD_HEADER SUS_header;
|
|
USHORT entry_length;
|
|
|
|
if ((SUSErrorLogHeader == NULL) || (SUSErrorLogData == NULL)) {
|
|
return -1;
|
|
}
|
|
|
|
if (UNREAD_BYTES_IN_LOG) {
|
|
|
|
SUS_header = (PSUS_ERROR_RECORD_HEADER)ADDRESS_OF(FIRST_UNREAD_RECORD);
|
|
entry_length = SUS_header->RecordLength;
|
|
|
|
if (entry_length > HAL_MAX_SUS_ENTRY_SIZE) {
|
|
entry_length = HAL_MAX_SUS_ENTRY_SIZE;
|
|
}
|
|
|
|
RtlMoveMemory(ErrorEntry,SUS_header,entry_length);
|
|
|
|
UNREAD_BYTES_IN_LOG -= SUS_header->RecordLength;
|
|
FIRST_UNREAD_RECORD += SUS_header->RecordLength;
|
|
|
|
if ((FIRST_UNREAD_RECORD == LOGICAL_LOG_END) &&
|
|
(UNREAD_BYTES_IN_LOG)) {
|
|
|
|
FIRST_UNREAD_RECORD = 0;
|
|
}
|
|
|
|
} else {
|
|
entry_length = 0;
|
|
}
|
|
return entry_length;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
HalSetWatchDogPeriod (
|
|
ULONG Period
|
|
)
|
|
|
|
{
|
|
if (SUSMailbox) {
|
|
SUSMailbox->OSFlags |= UPDATING_WDPERIOD;
|
|
SUSMailbox->WatchDogPeriod = Period;
|
|
SUSMailbox->WatchDogCount = 0;
|
|
SUSMailbox->OSFlags &= ~UPDATING_WDPERIOD;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
HalBumpWatchDogCount (
|
|
)
|
|
|
|
{
|
|
if (SUSMailbox) {
|
|
SUSMailbox->WatchDogCount++;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
HalpBeginSUSErrorEntry (
|
|
ULONG EntryType,
|
|
ULONG EntrySize
|
|
)
|
|
|
|
{
|
|
USHORT record_length;
|
|
PSUS_ERROR_RECORD_HEADER SUS_header;
|
|
|
|
USHORT i;
|
|
|
|
|
|
//
|
|
// Make sure the log is in a good state.
|
|
//
|
|
|
|
if (!HalpCheckSUSLogSanity()) {
|
|
CurrentSUSErrorEntryPosition = NULL;
|
|
CurrentSUSErrorEntryBytesRemaining = 0;
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Make sure the Error Entry is valid
|
|
//
|
|
|
|
if ((EntryType != NST_ErrorType) && (EntryType != ASCII_ErrorType)) {
|
|
return;
|
|
}
|
|
|
|
|
|
record_length = EntrySize + sizeof(SUS_ERROR_RECORD_HEADER);
|
|
|
|
//
|
|
// increate by 1 for the null terminator
|
|
//
|
|
record_length++;
|
|
|
|
|
|
//
|
|
// is it too big to fit?
|
|
//
|
|
|
|
if (record_length > PHYS_LOG_END)
|
|
return;
|
|
|
|
/* Check for fit before physical end of log */
|
|
/*
|
|
* if this record will NOT fit within physical end of log,
|
|
* it causes a wrap of the error log
|
|
* if the log is in a wrapped state, valid records at end of log will
|
|
* be lost
|
|
* Delete the valid bytes that are at the end of the log
|
|
* Point first valid to top of log
|
|
* if first unread will be lost in the wrap, unread records at the
|
|
* end of the log will be lost
|
|
* Delete the unread bytes that are at the end of the log
|
|
* Point first unread to top of log
|
|
* Set new logical end to where next record was to write
|
|
* Set next write record to the top of the log
|
|
*/
|
|
|
|
if ((record_length + NEXT_WRITE_RECORD) > PHYS_LOG_END) {
|
|
if (FIRST_VALID_RECORD >= NEXT_WRITE_RECORD) {
|
|
VALID_BYTES_IN_LOG -= LOGICAL_LOG_END - FIRST_VALID_RECORD;
|
|
FIRST_VALID_RECORD = 0;
|
|
}
|
|
if (FIRST_UNREAD_RECORD >= NEXT_WRITE_RECORD) {
|
|
UNREAD_BYTES_IN_LOG -= LOGICAL_LOG_END - FIRST_UNREAD_RECORD;
|
|
FIRST_UNREAD_RECORD = 0;
|
|
}
|
|
LOGICAL_LOG_END = NEXT_WRITE_RECORD;
|
|
NEXT_WRITE_RECORD = 0;
|
|
}
|
|
|
|
|
|
/* Check for overwriting currently unread records */
|
|
|
|
while(UNREAD_BYTES_IN_LOG && (NEXT_WRITE_RECORD <= FIRST_UNREAD_RECORD) &&
|
|
((record_length + NEXT_WRITE_RECORD) > FIRST_UNREAD_RECORD)) {
|
|
|
|
UNREAD_BYTES_IN_LOG -= RECORDLENGTH(ADDRESS_OF(FIRST_UNREAD_RECORD));
|
|
FIRST_UNREAD_RECORD += RECORDLENGTH(ADDRESS_OF(FIRST_UNREAD_RECORD));
|
|
|
|
if (FIRST_UNREAD_RECORD >= LOGICAL_LOG_END) {
|
|
FIRST_UNREAD_RECORD = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/* Check for overwriting currently valid records */
|
|
|
|
while (VALID_BYTES_IN_LOG && (NEXT_WRITE_RECORD <= FIRST_VALID_RECORD)&&
|
|
((record_length + NEXT_WRITE_RECORD) > FIRST_VALID_RECORD)) {
|
|
|
|
VALID_BYTES_IN_LOG -= RECORDLENGTH(ADDRESS_OF(FIRST_VALID_RECORD));
|
|
FIRST_VALID_RECORD += RECORDLENGTH(ADDRESS_OF(FIRST_VALID_RECORD));
|
|
if (FIRST_VALID_RECORD >= LOGICAL_LOG_END) {
|
|
FIRST_VALID_RECORD = 0;
|
|
LOGICAL_LOG_END = VALID_BYTES_IN_LOG;
|
|
}
|
|
}
|
|
|
|
UNREAD_BYTES_IN_LOG += record_length;
|
|
VALID_BYTES_IN_LOG += record_length;
|
|
|
|
SUS_header = (PSUS_ERROR_RECORD_HEADER)ADDRESS_OF(NEXT_WRITE_RECORD);
|
|
|
|
RtlZeroMemory((PVOID)SUS_header, (ULONG)record_length);
|
|
|
|
SUS_header->RecordType = EntryType;
|
|
SUS_header->RecordLength = record_length;
|
|
|
|
CurrentSUSErrorEntryPosition = (PUCHAR)ADDRESS_OF(NEXT_WRITE_RECORD) +
|
|
sizeof(SUS_ERROR_RECORD_HEADER);
|
|
|
|
CurrentSUSErrorEntryBytesRemaining = EntrySize;
|
|
|
|
/*
|
|
* Adjust all of the offsets to include the new record.
|
|
*/
|
|
|
|
NEXT_WRITE_RECORD += record_length;
|
|
|
|
if (NEXT_WRITE_RECORD > LOGICAL_LOG_END)
|
|
LOGICAL_LOG_END = NEXT_WRITE_RECORD;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
HalpWriteToSUSErrorEntry (
|
|
PUCHAR EntryData
|
|
)
|
|
|
|
{
|
|
USHORT entry_length;
|
|
USHORT i;
|
|
PUCHAR char_pointer;
|
|
|
|
if (CurrentSUSErrorEntryBytesRemaining == 0) {
|
|
return;
|
|
}
|
|
|
|
entry_length = 0;
|
|
char_pointer = EntryData;
|
|
|
|
while (*char_pointer) {
|
|
char_pointer++;
|
|
entry_length++;
|
|
}
|
|
|
|
if (entry_length == 0)
|
|
return;
|
|
|
|
if (entry_length > CurrentSUSErrorEntryBytesRemaining) {
|
|
entry_length = CurrentSUSErrorEntryBytesRemaining;
|
|
}
|
|
|
|
|
|
//
|
|
// Copy Entry segment into the Error Log
|
|
//
|
|
|
|
RtlMoveMemory(CurrentSUSErrorEntryPosition,EntryData,entry_length);
|
|
|
|
CurrentSUSErrorEntryBytesRemaining -= entry_length;
|
|
CurrentSUSErrorEntryPosition += entry_length;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID HalpWriteCheckSum(
|
|
PUCHAR CheckSumStart,
|
|
PUCHAR CheckSumEnd,
|
|
PUCHAR CheckSumLowByte,
|
|
PUCHAR CheckSumHighByte
|
|
)
|
|
|
|
|
|
|
|
{
|
|
USHORT check_sum = 0;
|
|
USHORT zero_sum;
|
|
PUCHAR address;
|
|
UCHAR data;
|
|
|
|
|
|
for (address = CheckSumStart; address <= CheckSumEnd; address++) {
|
|
HalpGetCmosData(1,(ULONG)address,
|
|
(PUCHAR)&data,1);
|
|
check_sum = check_sum + data;
|
|
}
|
|
|
|
zero_sum = 0 - check_sum;
|
|
|
|
HalpSetCmosData(1,SUS_HIGH_AVAIL_XSUM_LOW,
|
|
(PUCHAR)&zero_sum,2);
|
|
}
|
|
|
|
|
|
|
|
|