/*++
Copyright (c) 1993 NCR Corporation
Module Name:
ncrcat.c
Abstract:
Provides the interface to the NCR CAT bus.
Author:
Rick Ulmer (rick.ulmer@columbiasc.ncr.com) 29-Jul-1993
Revision History:
--*/
#include "halp.h"
#include "ncr.h"
#include "ncrcat.h"
#include "ncrcatp.h"
#include "ncrpsi.h"
#include "ncrarb.h"
VOID HalpAcquireCatBusSpinLock();
VOID HalpReleaseCatBusSpinLock();
PMODULE NCRCatModuleList = NULL;
PMODULE NCRCatModule = NULL;
USHORT NCRCatBasePort;
USHORT NCRCatCommandPort;
USHORT NCRCatDataPort;
SHORT NCRMinModuleAddress = 0;
SHORT NCRMaxModuleAddress = PSI;
//
// Used to signal HalReturnToFirmware to powerdown instead of reboot
//
BOOLEAN NCRPowerOffSystem = FALSE;
extern ULONG NCRLarcEnabledPages[]; // LARC size by Voyager slot
/*
* Function prototypes
*/
PMODULE
NCRCatModulePresent(
IN UCHAR ModuleAddress
);
UCHAR
NCRCatSubModulePresent(
);
PUCHAR
NCRCatReadModuleData(
);
VOID
NCRCatExtractSetupInformation(
PUCHAR EEpromData
);
VOID
NCRCatDefaultSetupInformation(
);
PMODULE
NCRCatSelect(
UCHAR ModuleAddress
);
PASIC
NCRCatGetAsic(
UCHAR AsicId
);
LONG
NCRCatConnect(
);
LONG
NCRCatDisconnect(
);
VOID
NCRCatRestoreState(
);
LONG
NCRCatAutoIncrement(
PASIC Asic
);
LONG
NCRCatNoAutoIncrement(
PASIC Asic
);
LONG
NCRCatSubaddressSetup(
PASIC Asic,
USHORT Subaddress
);
LONG
NCRCatRegisterIo(
PASIC Asic,
PCAT_CONTROL CatControl,
PUCHAR Buffer
);
LONG
NCRCatSubaddressIo(
PASIC Asic,
PCAT_CONTROL CatControl,
PUCHAR Buffer
);
LONG
NCRCatRead(
PASIC Asic,
UCHAR RegisterNumber,
PUCHAR Buffer
);
LONG
NCRCatWrite(
PASIC Asic,
UCHAR RegisterNumber,
PUCHAR Data
);
LONG
NCRCatSubaddressRead(
PASIC Asic,
PCAT_CONTROL CatControl,
PUCHAR Buffer
);
LONG
NCRCatWriteComplete(
PASIC Asic,
USHORT Address,
UCHAR Expected
);
LONG
NCRCatSubaddressWrite(
PASIC Asic,
PCAT_CONTROL CatControl,
PUCHAR Buffer
);
UCHAR
NCRCatInstruction(
UCHAR RegisterNumber,
UCHAR Operation
);
LONG
NCRCatSendInstruction(
PASIC Asic,
UCHAR Instruction
);
VOID
NCRCatBuildHeader(
PUCHAR Header,
SHORT HeaderBytes,
SHORT LargestRegister,
SHORT SmallestRegister
);
LONG
NCRCatSendData(
PASIC Aisc,
PUCHAR Data,
LONG InternalRegister,
LONG ExternalSpecial
);
VOID
NCRCatInsertData(
PUCHAR String,
SHORT StartBit,
PUCHAR Data,
SHORT NumberOfBits
);
VOID
NCRCatExtractData(
PUCHAR String,
SHORT StartBit,
PUCHAR Data,
SHORT NumberOfBits
);
LONG
NCRCatShiftOutData(
PUCHAR Data,
SHORT DataBytes,
SHORT HeaderBytes,
SHORT PadBits
);
LONG
NCRCatGetData(
PASIC Asic,
PUCHAR Data,
LONG InternalRegister
);
LONG
NCRCatIoLpb(
PCAT_CONTROL CatControl,
PUCHAR Buffer
);
VOID
NCRCatModuleName (
LONG Module,
PUNICODE_STRING ModuleName
);
VOID
NCRCatAsicName (
LONG Module,
LONG Asic,
PUNICODE_STRING AsicName
);
/*
* End of function prototypes.
*/
BOOLEAN
HalCatBusAvailable (
)
/*++
Routine Description:
Check to see if the Cat Bus is available on this system. If no modules
are found then the Cat Bus is not available.
Arguments:
None.
Return Value:
TRUE - Cat Bus is available.
FALSE - Cat Bus is not available
--*/
{
if (NCRCatModuleList) {
return TRUE;
} else {
return FALSE;
}
}
LONG
HalCatBusIo (
IN PCAT_CONTROL CatControl,
IN OUT PUCHAR Buffer
)
/*++
Routine Description:
Arguments:
CatControl -
Buffer -
Return Value:
--*/
{
LONG status;
#ifdef CATDEBUG
ULONG i;
PUCHAR pos;
#endif // CATDEBUG
/*
* Get the Cat bus lock.
*/
HalpAcquireCatBusSpinLock();
/*
* Perform the Cat bus function
*/
status = HalpCatBusIo(CatControl,Buffer);
/*
* Release the Cat Bus lock.
*/
HalpReleaseCatBusSpinLock();
#ifdef CATDEBUG
DBGMSG(("HalCatBusIo: Module 0x%x, Asic 0x%x, Address 0x%x\n", CatControl->Module, CatControl->Asic, CatControl->Address));
if (status == CATNOERR) {
if ((CatControl->Command == READ_REGISTER) || (CatControl->Command == READ_SUBADDR))
{
DBGMSG(("\tRead Data: "));
pos = Buffer;
for ( i = 0; i < CatControl->NumberOfBytes; i++ )
{
DBGMSG(("0x%2x ", *pos++));
}
DBGMSG(("\n"));
}
else
{
DBGMSG(("\tWrote Data: "));
pos = Buffer;
for ( i = 0; i < CatControl->NumberOfBytes; i++ )
{
DBGMSG(("0x%2x ", *pos++));
}
DBGMSG(("\n"));
}
} else {
DBGMSG(("HalCatBusIo Error: Status = 0x%x\n", status));
}
#endif // CATDEBUG
return status;
}
VOID
HalCatBusReset (
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NCRCatRestoreState();
}
LONG
HalpCatBusIo (
IN PCAT_CONTROL CatControl,
IN OUT PUCHAR Buffer
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PASIC asic;
LONG status;
/*
* Special processing required since LPB is not on the CAT bus.
*/
if (CatControl->Module == CAT_LPB_MODULE) {
status = NCRCatIoLpb(CatControl, Buffer);
return (status);
}
/*RMU add code here to detect if the CAT bus has been reset.... */
WRITE_PORT_UCHAR((PUCHAR)SELECT_PORT, (UCHAR)DESELECT);
if ((NCRCatSelect(CatControl->Module)) == NULL)
status = CATNOMOD;
else if ((asic = NCRCatGetAsic(CatControl->Asic)) == NULL)
status = CATNOASIC;
else {
switch(CatControl->Command) {
case READ_REGISTER:
case WRITE_REGISTER:
status = NCRCatRegisterIo(asic, CatControl, Buffer);
break;
case READ_SUBADDR:
case WRITE_SUBADDR:
status = NCRCatSubaddressIo(asic, CatControl, Buffer);
break;
default:
status = CATINVAL;
break;
}
}
/*
* UNIX guys took this out because of problems, so we will too.
*
if (status == CATIO) {
NCRCatRestoreState();
} else {
*/
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
/*
}
*/
WRITE_PORT_UCHAR((PUCHAR)SELECT_PORT, (UCHAR)DESELECT);
return (status);
}
VOID
HalpInitializeCatBusDriver (
)
/*++
Routine Description:
Read the ASIC information for each module from the subaddress space
of the CAT_I ASIC (EEPROM).
Arguments:
None
Return Value:
None
--*/
{
PMODULE *module_p;
UCHAR module_address, number_submodule, *data;
CAT_CONTROL cat_control;
UCHAR cat_data;
/*
* Get the Command and Data Port address
*/
NCRCatBasePort = (USHORT)(READ_PORT_UCHAR((PUCHAR)BASE_PORT) << 8);
NCRCatCommandPort = NCRCatBasePort + COMMAND_OFFSET;
NCRCatDataPort = NCRCatBasePort + DATA_OFFSET;
/*
* For each module that is present, build a data structure for the
* module and each of its ASICs.
*/
for (module_p = &NCRCatModuleList, module_address = (UCHAR)NCRMinModuleAddress;
module_address <= (UCHAR)NCRMaxModuleAddress; module_address++) {
WRITE_PORT_UCHAR((PUCHAR)SELECT_PORT, (UCHAR)DESELECT);
WRITE_PORT_UCHAR((PUCHAR)SELECT_PORT, (UCHAR)module_address);
if (((NCRCatModule = *module_p = NCRCatModulePresent(module_address))) == NULL) {
continue;
}
/*
* For 16way there way be submodules in addition to modules; if a
* submodule is present but the eeprom image is bad, just continue.
* This should never happen since firmware has already checked it.
*/
if ((number_submodule = NCRCatSubModulePresent()) > 0) {
PMODULE parent_module;
UCHAR submodule_data, submodule;
LONG status;
parent_module = NCRCatModule;
for (NCRCatModule = NCRCatModule->SubModules, submodule = 1; NCRCatModule != NULL;
NCRCatModule = NCRCatModule->Next, submodule++) {
/*
* Select the submodule by reading the SUBMODSELECT register
* (register 8). The most significant bit (bit 7) is the hold
* bit and should always be set to zero; bits 2-6 should not be
* altered; bits 0-1 will contain the submod that is to be
* selected. An ASIC structure for the CAT_I was allocated by
* NCRCatModulePresent().
*/
cat_control.Module = NCRCatModule->ModuleAddress;
cat_control.Asic = CAT_I;
cat_control.Command = READ_REGISTER;
cat_control.Address = SUBMODSELECT;
cat_control.NumberOfBytes = 1;
status = NCRCatRegisterIo(NCRCatModule->Asic, &cat_control,
(PUCHAR)&submodule_data);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
if (status)
continue;
submodule_data = (submodule_data & 0x7C) | submodule;
cat_control.Module = NCRCatModule->ModuleAddress;
cat_control.Asic = CAT_I;
cat_control.Command = WRITE_REGISTER;
cat_control.Address = SUBMODSELECT;
cat_control.NumberOfBytes = 1;
status = NCRCatRegisterIo(NCRCatModule->Asic, &cat_control,
(PUCHAR)&submodule_data);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
if (status)
continue;
if ((data = NCRCatReadModuleData()) != NULL)
NCRCatExtractSetupInformation(data);
}
NCRCatModule = parent_module;
} else {
if ((data = NCRCatReadModuleData()) == NULL) {
NCRCatDefaultSetupInformation();
} else {
NCRCatExtractSetupInformation(data);
}
}
module_p = &NCRCatModule->Next;
}
*module_p = NULL;
WRITE_PORT_UCHAR((PUCHAR)SELECT_PORT, (UCHAR)DESELECT);
//
// Lets steer all hardware failures to NMI and not SYSINT
// after this setup SYSINT should not occur.
//
cat_control.Module = PRIMARYMC;
cat_control.Asic = PMC_ARB;
cat_control.Command = WRITE_REGISTER;
cat_control.Address = SBA_SysInt_Enables;
cat_control.NumberOfBytes = 1;
cat_data = 0x0; // Disable all SYS_INT interrupts
HalCatBusIo(&cat_control, &cat_data);
cat_control.Address = SBA_GNMI_Enables;
cat_control.NumberOfBytes = 1;
cat_data = 0xff; // Enable all G_NMI interrupts
HalCatBusIo(&cat_control, &cat_data);
}
PMODULE
NCRCatModulePresent(
IN UCHAR ModuleAddress
)
/*++
Routine Description:
Determine if the module is present.
Arguments:
Return Value:
--*/
{
PMODULE module;
UCHAR input;
WRITE_PORT_UCHAR((PUCHAR)SELECT_PORT, (UCHAR)ModuleAddress);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)IRCYC);
WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)HEADER);
WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)0xAA);
input = READ_PORT_UCHAR((PUCHAR)NCRCatDataPort);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
if (input != HEADER) {
return (NULL);
}
/*
* If the module is present, allocate a data structure and
* assign the default values so we can later do a read.
*/
if ((module = (PMODULE)ExAllocatePool(NonPagedPool,sizeof(MODULE))) != NULL) {
RtlZeroMemory((PVOID)module,sizeof(MODULE));
module->ModuleAddress = ModuleAddress;
module->EEpromSize = EEPROM_SIZE;
module->ScanPathConnected = FALSE;
}
return (module);
}
UCHAR
NCRCatSubModulePresent(
)
/*++
Routine Description:
Determine if the module has submodules for 16way.
Arguments:
Return Value:
--*/
{
PMODULE submodule, *submodule_p;
CAT_CONTROL cat_control;
UCHAR number_submodules, submodule_present;
LONG status, i;
/*
* Submodules are unique to the processor boards.
*/
if( !((NCRCatModule->ModuleAddress >= PROCESSOR0 &&
NCRCatModule->ModuleAddress <= PROCESSOR3) ||
(NCRCatModule->ModuleAddress >= PROCESSOR4 &&
NCRCatModule->ModuleAddress <= PROCESSOR7)) )
return(0);
/*
* Allocate and define an ASIC data structure for the CAT_I so we can
* do our first read.
*/
if (NCRCatModule->Asic == NULL) {
if (!(NCRCatModule->Asic =
(PASIC)ExAllocatePool(NonPagedPool,sizeof(ASIC)))) {
return(0);
}
RtlZeroMemory((PVOID)NCRCatModule->Asic, sizeof(ASIC));
NCRCatModule->Asic->AsicId = CAT_I;
NCRCatModule->Asic->SubaddressSpace = SUBADDR_HI;
}
/*
* Read the SUBMODPRESENT register (register 9) of CAT_I to determine
* if there are any submodules present. If there are, allocate a
* module_t structure for each.
*/
cat_control.Module = NCRCatModule->ModuleAddress;
cat_control.Asic = CAT_I;
cat_control.Command = READ_REGISTER;
cat_control.Address = SUBMODPRESENT;
cat_control.NumberOfBytes = 1;
status = NCRCatRegisterIo(NCRCatModule->Asic, &cat_control, (PUCHAR)&number_submodules);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
if (status)
return(0);
/*
* The two least significant bits of the SUBMODPRESENT register contain the
* number of submodules. These bits are active low.
* muoe941414 - jtt - 4/28/94
* These bits actually tell which submodules are present (each one
* representing a submodule). Submodpres is a bit place indicator
* of what modules are present (there is always a base board - 1 in
* lowest position).
*/
number_submodules = ~(number_submodules | 0xFC);
if(number_submodules)
submodule_present = (number_submodules << BASE_BOARD_SHIFT) | BASE_BOARD_PRESENT;
else
submodule_present = 0;
/*
* For each submodule, allocate a submodule structure and fill in
* default values for the eeprom read.
*/
submodule_p = &(NCRCatModule->SubModules);
for (i = 1; number_submodules != 0, i <= MAXSUBMOD; i++) {
/*
* muoe941414 - jtt - 4/28/94
* check first if submodule is present (corresponding bit set in
* submodpres string
*/
if (!(submodule_present & (1 << (i - 1))))
continue;
if ((*submodule_p = submodule = (PMODULE)ExAllocatePool(NonPagedPool,sizeof(MODULE))) != NULL) {
/*
* The submodule address is kept in the three most significant bits of
* the module address.
*/
RtlZeroMemory((PVOID)submodule, sizeof(MODULE));
submodule->ModuleAddress = ((i << 5) | NCRCatModule->ModuleAddress);
submodule->EEpromSize = EEPROM_SIZE;
submodule->ScanPathConnected = FALSE;
submodule_p = &submodule->Next;
/*
* Allocate a ASIC structure for CAT_I for each submodule; we will need
* it to select the submodle when we return to catinit_L5().
*/
if (!(submodule->Asic = (PASIC)ExAllocatePool(NonPagedPool,sizeof(ASIC)))) {
ExFreePool((PVOID)submodule);
*submodule_p = NULL;
return(i - 1);
}
RtlZeroMemory((PVOID)submodule->Asic, sizeof(ASIC));
submodule->Asic->AsicId = CAT_I;
submodule->Asic->SubaddressSpace = SUBADDR_HI;
}
}
*submodule_p = NULL;
return(number_submodules);
}
PUCHAR
NCRCatReadModuleData(
)
/*++
Routine Description:
Read the module data from the EEPROM and checksum it. If the checksum
fails for any reason, a NULL pointer is returned. If the checksum is
correct a pointer to the EEPROM data is returned.
Arguments:
Return Value:
--*/
{
CAT_CONTROL cat_control;
PASIC asic;
USHORT xsum_end;
USHORT xsum;
PUSHORT data;
USHORT i;
USHORT size_of_eeprom;
LONG status;
/*
* Allocate and define an ASIC data structure for the CAT_I so we can do our first read.
* If it is a processor board, the CAT_I will have been allocated by NCRCatSubModulePresent.
* If an error occurs, do not free the Asic structure since we may or may not have creatd it and
* it will be needed by NCRCatDefaultSetup if we fail.
*/
if (NCRCatModule->Asic == NULL) {
if (!(asic = NCRCatModule->Asic = (PASIC)ExAllocatePool(NonPagedPool,sizeof(ASIC)))) {
return (NULL);
}
RtlZeroMemory((PVOID)asic, sizeof(ASIC));
asic->AsicId = CAT_I;
asic->SubaddressSpace = SUBADDR_HI;
} else {
asic = NCRCatModule->Asic;
}
/*
* Read the checksum offset from the EEPROM and make sure it looks valid.
*/
cat_control.Module = NCRCatModule->ModuleAddress;
cat_control.Asic = CAT_I;
cat_control.Command = READ_SUBADDR;
cat_control.Address = XSUM_END_OFFSET;
cat_control.NumberOfBytes = 2;
status = NCRCatSubaddressIo(asic,&cat_control,(PUCHAR)&xsum_end);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
if (status) {
return (NULL);
}
cat_control.Module = NCRCatModule->ModuleAddress;
cat_control.Asic = CAT_I;
cat_control.Command = READ_SUBADDR;
cat_control.Address = EEPROM_SIZE_OFFSET;
cat_control.NumberOfBytes = 2;
status = NCRCatSubaddressIo(asic,&cat_control,(PUCHAR)&size_of_eeprom);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
if (status) {
return (NULL);
}
if ((xsum_end < sizeof(MODULE_HEADER)) || (xsum_end > size_of_eeprom)) {
return (NULL);
}
/*
* Allocate a buffer for the data and read it from the EEPROM
*/
if ((data = (PUSHORT) ExAllocatePool(NonPagedPool, (ULONG)xsum_end)) == NULL) {
return (NULL);
}
RtlZeroMemory((PVOID)data,(ULONG)xsum_end);
cat_control.Address = EEPROM_DATA_START;
cat_control.NumberOfBytes = xsum_end;
status = NCRCatSubaddressIo(asic, &cat_control, (PUCHAR)data);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
if (status) {
ExFreePool((PVOID)data);
return (NULL);
}
/*
* Checksum the data to make sure it is valid.
*/
for (i = 0, xsum = 0; i < (USHORT)(xsum_end / 2); i++)
xsum += *((PUSHORT)(data +i));
if (xsum != 0) {
ExFreePool((PVOID)data);
return (NULL);
}
/*
* Return the EEPROM data. Also, as a side effect, the NCRCatModule->asic field
* is left pointing to the ASIC data structure that was allocated.
*/
return ((PUCHAR)data);
}
VOID
NCRCatExtractSetupInformation(
PUCHAR EEpromData
)
/*++
Routine Description:
Extract the setup information from the data read from the EEPROM.
Arguments:
Return Value:
--*/
{
PASIC asic, *asic_pointer;
PMODULE_HEADER module_header;
PSCAN_PATH_TABLE scan_path_table;
PASIC_DATA_TABLE asic_data_table;
PJTAG_TABLE jtag_table;
USHORT asic_number, scan_path_offset;
LONG i;
module_header = (PMODULE_HEADER)EEpromData;
NCRCatModule->EEpromSize = module_header->EEpromSize;
NCRCatModule->NumberOfAsics = module_header->NumberOfAsics;
for (asic_number = 0, asic = NCRCatModule->Asic, scan_path_offset = module_header->ScanPathOffset;
asic_number < module_header->NumberOfAsics; asic_number++, scan_path_offset +=
sizeof(SCAN_PATH_TABLE), asic_pointer = &asic->Next, asic = NULL) {
/*
* On the first pass, we have an asic that was allocated when the
* data block was read from the EEPROM.
*/
if (asic == NULL) {
if (!(asic = *asic_pointer = ExAllocatePool(NonPagedPool,sizeof(ASIC)))) {
ExFreePool((PVOID)EEpromData);
return;
}
RtlZeroMemory((PVOID)asic, sizeof(ASIC));
}
asic->AsicLocation = (UCHAR)asic_number;
/*
* Set up a pointer to the new scan path table
*/
scan_path_table = (PSCAN_PATH_TABLE)(EEpromData + scan_path_offset);
asic->AsicId = scan_path_table->AsicId;
/*
* Set up a pointer to the asic_data_table
*/
asic_data_table = (PASIC_DATA_TABLE)(EEpromData + scan_path_table->AsicDataOffset);
for (i = 0; i < 4; i++) {
asic->JtagId[i] = asic_data_table->JtagId[i];
}
asic->SubaddressSpace = ((1 << asic_data_table->SubaddressBits) - 1);
/*
* Set up a pointer to the jtab_table
*/
jtag_table = (PJTAG_TABLE)(EEpromData + asic_data_table->JtagOffset);
asic->InstructionRegisterLength = jtag_table->InstructionRegisterLength;
asic->BitLocation = (USHORT)NCRCatModule->InstructionBits;
NCRCatModule->InstructionBits += asic->InstructionRegisterLength;
if (asic->InstructionRegisterLength > NCRCatModule->LargestRegister) {
NCRCatModule->LargestRegister = asic->InstructionRegisterLength;
}
if (asic->InstructionRegisterLength < NCRCatModule->SmallestRegister ||
NCRCatModule->SmallestRegister == 0) {
NCRCatModule->SmallestRegister = asic->InstructionRegisterLength;
}
}
asic_pointer = NULL;
ExFreePool((PVOID)EEpromData);
}
VOID
NCRCatDefaultSetupInformation(
)
/*++
Routine Description:
Assign defaults to the module if the EEPROM checksum is not correct.
Arguments:
Return Value:
--*/
{
PASIC asic, *asic_pointer;
USHORT i;
switch (NCRCatModule->ModuleAddress) {
case PROCESSOR0:
case PROCESSOR1:
case PROCESSOR2:
case PROCESSOR3:
case PROCESSOR4:
case PROCESSOR5:
case PROCESSOR6:
case PROCESSOR7:
NCRCatModule->EEpromSize = EEPROM_SIZE;
NCRCatModule->NumberOfAsics = 1;
break;
case MEMORY0:
case MEMORY1:
NCRCatModule->EEpromSize = EEPROM_SIZE;
NCRCatModule->NumberOfAsics = 7;
break;
case PRIMARYMC:
NCRCatModule->EEpromSize = EEPROM_SIZE;
NCRCatModule->NumberOfAsics = 9;
break;
case SECONDARYMC:
NCRCatModule->EEpromSize = EEPROM_SIZE;
NCRCatModule->NumberOfAsics = 7;
break;
case PSI:
NCRCatModule->EEpromSize = PSI_EEPROM_SIZE;
NCRCatModule->NumberOfAsics = 1;
break;
default:
NCRCatModule->EEpromSize = EEPROM_SIZE;
NCRCatModule->NumberOfAsics = 1;
break;
}
NCRCatModule->InstructionBits = NCRCatModule->NumberOfAsics * CHAR_SIZE;
NCRCatModule->LargestRegister = 8;
NCRCatModule->SmallestRegister = 8;
NCRCatModule->SubModules = NULL;
for (i = 0, asic = NCRCatModule->Asic,asic_pointer = &NCRCatModule->Asic;
i < NCRCatModule->NumberOfAsics; i++) {
if (*asic_pointer == NULL) {
if (!(asic = *asic_pointer = ExAllocatePool(NonPagedPool,sizeof(ASIC)))) {
return;
}
}
RtlZeroMemory((PVOID)asic,sizeof(ASIC));
asic->AsicId = (UCHAR)i;
asic->AsicLocation = (UCHAR)i;
asic->BitLocation = (UCHAR)(i * CHAR_SIZE);
asic->InstructionRegisterLength = 8;
asic->SubaddressSpace = SUBADDR_HI;
asic_pointer = &asic->Next;
}
}
PMODULE
NCRCatSelect(
UCHAR ModuleAddress
)
/*++
Routine Description:
This function is used to select a module. If the module address matches the
address passed in, a pointer to the module structure is returned. Otherwise,
NULL is returned.
Arguments:
Return Value:
--*/
{
PMODULE module, submodule;
CAT_CONTROL cat_control;
UCHAR module_address, submodule_address, data;
LONG status;
/*
* Extract the real module and submodule addresses.
* If any of the three most significant bits of the module
* address are set, we have a submodule.
*/
submodule_address = ModuleAddress;
module_address = ModuleAddress & 0x1f;
for (module = NCRCatModuleList; module != NULL; module = module->Next) {
if (module->ModuleAddress != module_address)
continue;
//
// Select the module
//
WRITE_PORT_UCHAR((PUCHAR)SELECT_PORT, (UCHAR)module_address);
/*
* muoe941245 - jtt - 5/10/94
* If it is a submodule, "catmodule" is not set which
* can cause problems in the following catregio(),
* especially if it is NULL.
*/
NCRCatModule = module;
if (submodule_address == module_address)
return(module);
/*
* Must be looking for a submodule (16way). Select the
* submodule by writing the submodule address in the
* two least significant bits of the CAT_I;
*/
for (submodule = module->SubModules; submodule != NULL;
submodule = submodule->Next) {
if (submodule->ModuleAddress != submodule_address)
continue;
cat_control.Module = submodule->ModuleAddress;
cat_control.Asic = CAT_I;
cat_control.Command = WRITE_REGISTER;
cat_control.Address = SUBMODSELECT;
cat_control.NumberOfBytes = 1;
data = submodule->ModuleAddress >> 5;
status = NCRCatRegisterIo(submodule->Asic, &cat_control, (PUCHAR)&data);
if (!status) {
NCRCatModule = submodule;
} else {
NCRCatModule = NULL;
}
return(NCRCatModule);
}
/*
* Should not have to deselect here. The next operation will send a DESELECT.
*/
break;
}
NCRCatModule = NULL;
return (NULL);
}
PASIC
NCRCatGetAsic(
UCHAR AsicId
)
/*++
Routine Description:
Tries to match the AsicId with an AsicId in the current selected module.
If there is no match, NULL is returned.
Arguments:
Return Value:
--*/
{
PASIC asic;
for (asic = NCRCatModule->Asic; asic != NULL; asic = asic->Next) {
if (asic->AsicId == AsicId) {
return (asic);
}
}
return (NULL);
}
LONG
NCRCatConnect(
)
/*++
Routine Description:
Called to connect the CAT_I with all of the other ASICs on the module.
Arguments:
Return Value:
--*/
{
PASIC asic;
UCHAR value;
LONG status;
if (NCRCatModule->ScanPathConnected == TRUE) {
return (CATNOERR);
}
if (!(asic = NCRCatGetAsic(CAT_I))) {
return (CATIO);
}
if (status = NCRCatRead(asic, SCANPATH, &value)) {
return (status);
}
value |= CONNECT_ASICS;
if (status = NCRCatWrite(asic, SCANPATH, &value)) {
return (status);
}
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
NCRCatModule->ScanPathConnected = TRUE;
return (CATNOERR);
}
LONG
NCRCatDisconnect(
)
/*++
Routine Description:
Called to disconnect the CAT_I from all the ASICs on the module.
Arguments:
Return Value:
--*/
{
PASIC asic;
UCHAR value;
LONG status;
if (NCRCatModule->ScanPathConnected == FALSE) {
return (CATNOERR);
}
if (!(asic = NCRCatGetAsic(CAT_I))) {
return (CATIO);
}
if (status = NCRCatRead(asic, SCANPATH, &value)) {
return (status);
}
value &= DISCONNECT_ASIC;
if (status = NCRCatWrite(asic, SCANPATH, &value)) {
return (status);
}
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
NCRCatModule->ScanPathConnected = FALSE;
return (CATNOERR);
}
VOID
NCRCatRestoreState(
)
/*++
Routine Description:
This function is called when an I/O error has occured. The best thing to do
is to do a blind disconnect and hope this fixes the problem.
Arguments:
Return Value:
--*/
{
UCHAR instruction;
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)IRCYC); // Instruct the module
instruction = NCRCatInstruction(SCANPATH, WRITE_CONFIG);
WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)instruction);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)DRCYC);
WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)RESET_STATE);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
NCRCatModule->ScanPathConnected = FALSE;
}
LONG
NCRCatAutoIncrement(
PASIC Asic
)
/*++
Routine Description:
When reading/writing from/to the subaddress space of an ASIC, the catautoinc bit
can be set so that registers 6 & 7 are incremented by the hardware after each
read/write from/to register 3.
Arguments:
Return Value:
--*/
{
UCHAR newvalue;
UCHAR oldvalue;
LONG status;
if (status = NCRCatRead(Asic, AUTO_INC_REG, &oldvalue)) {
return (status);
}
if ((newvalue = (oldvalue | AUTO_INC)) != oldvalue) {
status = NCRCatWrite(Asic, AUTO_INC_REG, &newvalue);
}
return status;
}
LONG
NCRCatNoAutoIncrement(
PASIC Asic
)
/*++
Routine Description:
This function is used to reset the auto increment bit for subaddress reads/writes.
This allows reads/writes from/to the subaddress space via register 3 with out
incrementing registers 6 & 7.
Arguments:
Return Value:
--*/
{
UCHAR newvalue;
UCHAR oldvalue;
LONG status;
if (status = NCRCatRead(Asic, AUTO_INC_REG, &oldvalue)) {
return (status);
}
if ((newvalue = (oldvalue & NO_AUTO_INC)) != oldvalue) {
status = NCRCatWrite(Asic, AUTO_INC_REG, &newvalue);
}
return (status);
}
LONG
NCRCatSubaddressSetup(
PASIC Asic,
USHORT Subaddress
)
/*++
Routine Description:
Sets up register 6 & 7 for a subaddress read. Note: If the subaddres space
requires 8 bits or less for addressing, register 7 may be user defined. If
there is no subaddress space registers 6 & 7 may be user defined.
Arguments:
Return Value:
--*/
{
LONG status;
UCHAR address;
if (Asic->SubaddressSpace == (USHORT)SUBADDR_ZERO) {
return (CATIO);
}
/*
* Set up register 6 with the low byte of the sub address
*/
address = (UCHAR)(Subaddress & 0xff);
if (status = NCRCatWrite(Asic, SUBADDRLO, &address)) {
return (status);
}
/*
* Set up register 7 with the high byte of the sub address
*/
if (Asic->SubaddressSpace > SUBADDR_LO) {
address = (UCHAR)(Subaddress >> CHAR_SIZE);
status = NCRCatWrite(Asic, SUBADDRHI, &address);
}
return (status);
}
LONG
NCRCatRegisterIo(
PASIC Asic,
PCAT_CONTROL CatControl,
PUCHAR Buffer
)
/*++
Routine Description:
The function is used to read/write from/to any number of register of an ASIC.
If a read is being performed, the buffer is assumed to be large enough to
hold the data that is being read.
Arguments:
Return Value:
--*/
{
UCHAR register_number;
PUCHAR buffer;
USHORT number_bytes;
LONG status;
if ((USHORT)(CatControl->Address + CatControl->NumberOfBytes) > (USHORT)MAXNUMREG) {
return (CATFAULT);
}
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
if (Asic->AsicId == CAT_I) {
if (status = NCRCatDisconnect()) {
return (status);
}
} else {
if (status = NCRCatConnect()) {
return (status);
}
}
if (CatControl->Command == READ_REGISTER) {
for (register_number = (UCHAR)CatControl->Address, number_bytes = CatControl->NumberOfBytes,
buffer = Buffer; number_bytes > 0;
register_number++, number_bytes--, buffer++) {
if (status = NCRCatRead(Asic, register_number, buffer)) {
return (status);
}
}
} else { /* CatControl->Command == WRITE_REGISTER */
for (register_number = (UCHAR)CatControl->Address, number_bytes = CatControl->NumberOfBytes,
buffer = Buffer; number_bytes > 0;
register_number++, number_bytes--, buffer++) {
if (status = NCRCatWrite(Asic, register_number, buffer)) {
return (status);
}
}
}
if (Asic->AsicId != CAT_I) {
status = NCRCatDisconnect();
}
return (status);
}
LONG
NCRCatSubaddressIo(
PASIC Asic,
PCAT_CONTROL CatControl,
PUCHAR Buffer
)
/*++
Routine Description:
This function is used to read/write from/to the subaddress space of an ASIC.
If a read is being performed, the buffer is assumed to be large enough to hold
the data that is being read.
Arguments:
Return Value:
--*/
{
LONG status;
if ((ULONG)(CatControl->Address + CatControl->NumberOfBytes - 1) > Asic->SubaddressSpace) {
return (CATFAULT);
}
if ((CatControl->Module >= PROCESSOR0 && CatControl->Module <= PROCESSOR3 ||
CatControl->Module >= PROCESSOR4 && CatControl->Module <= PROCESSOR7) &&
((ULONG)(CatControl->Address + CatControl->NumberOfBytes) >
(ULONG)NCRCatModule->EEpromSize)) {
return (CATACCESS);
}
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
if (Asic->AsicId == CAT_I) {
if (status = NCRCatDisconnect())
return (status);
} else { /* Asic->AsicId != CAT_I */
if (status = NCRCatConnect())
return (status);
}
if (CatControl->Command == READ_SUBADDR) {
if (status = NCRCatSubaddressRead(Asic, CatControl, Buffer))
return (status);
} else {
if (status = NCRCatSubaddressWrite(Asic, CatControl, Buffer))
return (status);
}
if (Asic->AsicId != CAT_I)
status = NCRCatDisconnect();
return (status);
}
LONG
NCRCatRead(
PASIC Asic,
UCHAR RegisterNumber,
PUCHAR Buffer
)
/*++
Routine Description:
Function used to read one register from one asic at a time.
Arguments:
Return Value:
--*/
{
LONG status;
LONG internal_register = TRUE;
UCHAR instruction;
instruction = NCRCatInstruction(RegisterNumber, READ_CONFIG);
if (status = NCRCatSendInstruction(Asic, instruction))
return (status);
if (RegisterNumber > SUBADDRHI)
internal_register = FALSE;
if (status = NCRCatGetData(Asic, Buffer, internal_register))
return (status);
return (status);
}
LONG
NCRCatWrite(
PASIC Asic,
UCHAR RegisterNumber,
PUCHAR Data
)
/*++
Routine Description:
Function used to write to one register of one ASIC at a time. It
is assumed that the CatSelect call has already been used to select
the desired module.
Arguments:
Return Value:
--*/
{
LONG status;
LONG internal_register = TRUE;
LONG external_special = FALSE;
UCHAR instruction;
instruction = NCRCatInstruction(RegisterNumber, WRITE_CONFIG);
if (status = NCRCatSendInstruction(Asic, instruction))
return (status);
if (RegisterNumber > SUBADDRHI) {
internal_register = FALSE;
if (RegisterNumber < MAXNUMREG) {
external_special = TRUE;
}
}
if (status = NCRCatSendData(Asic, Data, internal_register, external_special))
return (status);
return (status);
}
LONG
NCRCatSubaddressRead(
PASIC Asic,
PCAT_CONTROL CatControl,
PUCHAR Buffer
)
/*++
Routine Description:
Function used to read data from the subaddress space. If the CAT_I subaddress
space is being read (EEPROM), extra RUN cycles are required for the read.
Arguments:
Return Value:
--*/
{
UCHAR instruction;
PUCHAR buffer;
USHORT number_bytes;
LONG status;
if (CatControl->NumberOfBytes > 1) {
if (status = NCRCatAutoIncrement(Asic))
return (status);
}
if (status = NCRCatSubaddressSetup(Asic, CatControl->Address)) {
return (status);
}
instruction = NCRCatInstruction(SUBADDRDATA, READ_CONFIG);
if (status = NCRCatSendInstruction(Asic, instruction)) {
return (status);
}
for (number_bytes = CatControl->NumberOfBytes, buffer = Buffer; number_bytes > 0;
number_bytes--, buffer++) {
if (status = NCRCatGetData(Asic, buffer, FALSE))
break;
}
return (status);
}
LONG
NCRCatWriteComplete(
PASIC Asic,
USHORT Address,
UCHAR Expected
)
/*++
Routine Description:
Function used to determine if a write to the subaddress space of the CAT_I (EEPROM) has been
completed. The write is complete when the data read matches what was written. The data that
is read should be the one's complement of the data written until the write completes.
Arguments:
Return Value:
--*/
{
UCHAR data;
LONG status;
ULONG i, j;
UCHAR instruction;
if (status = NCRCatNoAutoIncrement(Asic))
return (status);
if (status = NCRCatSubaddressSetup(Asic, Address))
return (status);
for (i = 0; i < MAXREADS; i++) {
for ( j = 0; j < WRITEDELAY; j++)
KeStallExecutionProcessor((ULONG)10);
/* Old code
if (status = NCRCatRead(Asic, SUBADDRDATA, &data))
return(status);
*/
instruction = NCRCatInstruction(SUBADDRDATA, READ_CONFIG);
if (status = NCRCatSendInstruction(Asic,instruction))
return(status);
if (status = NCRCatGetData(Asic, &data, FALSE))
return(status);
if (data == Expected)
return (CATNOERR);
}
return (CATIO);
}
LONG
NCRCatSubaddressWrite(
PASIC Asic,
PCAT_CONTROL CatControl,
PUCHAR Buffer
)
/*++
Routine Description:
Function that writes to the subaddress space of an ASIC.
Arguments:
Return Value:
--*/
{
USHORT subaddress;
USHORT remaining_bytes;
USHORT number_bytes;
USHORT i;
UCHAR instruction;
PUCHAR buffer;
LONG status;
/*
* The CAT_I subaddress space (EEPROM) may be written one byte at
* time. However, the EEPROM waits for 20 microsec before starting
* the write. If an additional byte of data is received before the
* 20 microsec timeout, the EEPROM waits for yet another byte of data.
* This contiues until the 64 byte EEPROM buffer is filled or a timeout
* occures. At that point the data is written to the EEPROM.
*/
if ((CatControl->Asic == CAT_I) && (CatControl->Address < NCRCatModule->EEpromSize)) {
/*
* Write the data up to a page & then wait for the EEPROM write to complete.
*/
for (subaddress = CatControl->Address, remaining_bytes = CatControl->NumberOfBytes,
buffer = Buffer; remaining_bytes > 0; subaddress += number_bytes,
remaining_bytes -= number_bytes) {
number_bytes = EEPROMPAGESIZE - (USHORT)(subaddress % EEPROMPAGESIZE);
if (number_bytes > remaining_bytes)
number_bytes = remaining_bytes;
if (status = NCRCatAutoIncrement(Asic))
return (status);
if (status = NCRCatSubaddressSetup(Asic, subaddress))
return (status);
instruction = NCRCatInstruction(SUBADDRDATA, WRITE_CONFIG);
if (status = NCRCatSendInstruction(Asic, instruction))
return (status);
/*
* When writing to the EEPROM, error checking must be delayed until
* the the end of the block write. This is due to the amount of
* time it take to send data over the CAT bus and the EEPROM
* timeout.
*/
for (i = 0; i < number_bytes; i++) {
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)DRCYC);
WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)*buffer++);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
}
/*
* If the read starts in the PSI EEPROM and continues into the
* the subaddress space past the EEPROM the data compare must
* stop. Writing to this area toggles bits so the data that is
* written may not match what is read later.
*/
if ((ULONG)(subaddress + number_bytes - 1) < (ULONG)NCRCatModule->EEpromSize) {
/*
* Read the last byte and compare it with last byte written.
* The data should be the one's complement of the data written
* until the write completes.
*/
if (status = NCRCatWriteComplete(Asic, (USHORT)(subaddress + number_bytes - 1),
*(buffer - 1))) {
return (status);
}
}
}
} else { /* ((Aisc != CAT_I) || (CatControl->Address >= NCRCatControl->EEpromSize)) */
if (status = NCRCatAutoIncrement(Asic))
return (status);
if (status = NCRCatSubaddressSetup(Asic, CatControl->Address))
return (status);
instruction = NCRCatInstruction(SUBADDRDATA, WRITE_CONFIG);
if (status = NCRCatSendInstruction(Asic, instruction))
return (status);
for (number_bytes = CatControl->NumberOfBytes, buffer = Buffer; number_bytes > 0;
number_bytes--, buffer++) {
if (status = NCRCatSendData(Asic, buffer, FALSE, FALSE))
return (status);
}
}
return (CATNOERR);
}
UCHAR
NCRCatInstruction(
UCHAR RegisterNumber,
UCHAR Operation
)
/*++
Routine Description:
Function builds an instruction by determing the parity bit needed for
even parity and puting this value in bit 7 and zero in bit 6. The
register number is placed in bits 2-5 and the operation (read/write)
value in bits 0 and 1.
Arguments:
Return Value:
--*/
{
UCHAR parity;
/*
* Parity is the parity of the register number + 1 (READ_REGISTER
* and WRITE_REGISTER always add '1' to the number of bits == 1)
*/
parity = (UCHAR)(1 + (RegisterNumber & 0x01) +
((UCHAR)(RegisterNumber & 0x02) >> 1) +
((UCHAR)(RegisterNumber & 0x04) >> 2) +
((UCHAR)(RegisterNumber & 0x08) >> 3)) % 2;
return (((parity << 7) | (RegisterNumber << 2) | Operation));
}
LONG
NCRCatSendInstruction(
PASIC Asic,
UCHAR Instruction
)
/*++
Routine Description:
Function inserts an instruction inside of a string to be shifted
out of the NCRCatDataPort so that all of the ASICs execept the one we are
instructing will be placed in bypass mode. If the scan path has not been
connected, then we can only talk to the CAT_I. In this case, we have very
little work to do.
Arguments:
Return Value:
--*/
{
UCHAR instruction_sequence[MAX_SCAN_PATH];
UCHAR header_sequence[MAX_REG_SIZE];
SHORT i;
SHORT instruction_bytes;
SHORT header_bytes;
SHORT pad_bits;
LONG status = CATNOERR;
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)IRCYC);
if (NCRCatModule->ScanPathConnected == FALSE) {
WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)HEADER);
WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)Instruction);
if ((READ_PORT_UCHAR((PUCHAR)NCRCatDataPort)) != HEADER)
status = CATIO;
return (status);
}
instruction_bytes = NCRCatModule->InstructionBits / CHAR_SIZE;
if (pad_bits = NCRCatModule->InstructionBits % CHAR_SIZE) {
pad_bits = CHAR_SIZE - pad_bits;
instruction_bytes++;
}
header_bytes = NCRCatModule->LargestRegister / CHAR_SIZE;
if (NCRCatModule->LargestRegister % CHAR_SIZE)
header_bytes++;
for (i = 0; i < (instruction_bytes + header_bytes); i++) {
*(instruction_sequence + i) = 0xff;
}
NCRCatBuildHeader(header_sequence, header_bytes, NCRCatModule->LargestRegister,
NCRCatModule->SmallestRegister);
NCRCatInsertData(instruction_sequence, NCRCatModule->InstructionBits, header_sequence,
(SHORT)(header_bytes * CHAR_SIZE));
NCRCatInsertData(instruction_sequence, Asic->BitLocation, &Instruction,
Asic->InstructionRegisterLength);
status = NCRCatShiftOutData(instruction_sequence, instruction_bytes, header_bytes, pad_bits);
return (status);
}
VOID
NCRCatBuildHeader(
PUCHAR Header,
SHORT HeaderBytes,
SHORT LargestRegister,
SHORT SmallestRegister
)
/*++
Routine Description:
Function builds a header to be placed out on the CAT bus. It is used
to make sure that a register did not unexpectedly go into bypass.
Arguments:
Return Value:
--*/
{
SHORT one_bits;
SHORT i;
PUCHAR last_byte;
if (SmallestRegister == 1)
one_bits = 1;
else
one_bits = (USHORT)(SmallestRegister - 1) % CHAR_SIZE;
for (i = 0; i < HeaderBytes; i++)
*(Header+i) = 0;
for (i = one_bits, last_byte = (PUCHAR)(Header + (HeaderBytes - 1)); i > 0; i--)
*last_byte = ((*last_byte) << 1) + 1;
}
LONG
NCRCatSendData(
PASIC Asic,
PUCHAR Data,
LONG InternalRegister,
LONG ExternalRegister
)
/*++
Routine Description:
Function generates a sequence to be shifted out of the NCRCatDataPort
so that the data is send to the desired ASIC and an one is shifted to all
of the other ASICs (they are in bypass mode).
Arguments:
Return Value:
--*/
{
UCHAR data_sequence[MAX_SCAN_PATH];
UCHAR header_sequence[MAX_REG_SIZE];
SHORT i;
SHORT data_bytes;
SHORT header_bytes;
SHORT pad_bits;
SHORT header_location;
LONG status = CATNOERR;
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)DRCYC);
if (NCRCatModule->ScanPathConnected == FALSE) {
WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)HEADER);
WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)*Data);
if (READ_PORT_UCHAR((PUCHAR)NCRCatDataPort) != HEADER)
status = CATIO;
if (InternalRegister == FALSE) {
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
if (ExternalRegister == TRUE) {
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
}
}
return (status);
}
data_bytes = (SHORT)((NCRCatModule->NumberOfAsics - 1) + Asic->InstructionRegisterLength) /
(SHORT)CHAR_SIZE;
if (pad_bits = (SHORT)((NCRCatModule->NumberOfAsics - 1) +
Asic->InstructionRegisterLength) % (SHORT)CHAR_SIZE) {
pad_bits = CHAR_SIZE - pad_bits;
data_bytes++;
}
header_bytes = (SHORT)(Asic->InstructionRegisterLength / CHAR_SIZE);
if ((SHORT)(Asic->InstructionRegisterLength % CHAR_SIZE))
header_bytes++;
NCRCatBuildHeader(header_sequence, header_bytes, Asic->InstructionRegisterLength, 1);
for (i = 0; i < (data_bytes + header_bytes); i++)
*(data_sequence + i) = 0xff;
header_location = (NCRCatModule->NumberOfAsics - 1) + Asic->InstructionRegisterLength;
NCRCatInsertData(data_sequence, header_location, header_sequence, (SHORT)(header_bytes * CHAR_SIZE));
NCRCatInsertData(data_sequence, Asic->AsicLocation, Data, Asic->InstructionRegisterLength);
status = NCRCatShiftOutData(data_sequence, data_bytes, header_bytes, pad_bits );
return (status);
}
VOID
NCRCatInsertData(
PUCHAR String,
SHORT StartBit,
PUCHAR Data,
SHORT NumberOfBits
)
/*++
Routine Description:
Given a string, the function places the data inside of the string
starting a bit location string_bit. The most significant byte will
be placed in the first 8 bits starting at string_bit location. If
the data does not fall on a byte boundry, the data should be placed
in the high order bits. The low order bits should be padded with 1's.
The first byte of the string is considered the most significant byte
and should be the last byte shifted out.
Arguments:
Return Value:
--*/
{
SHORT data_bits; // running count of data bits placed in the string
SHORT data_bits_remaining; // data bits remaining in current char
SHORT string_bits_needed; // string bits needed to fill current char
SHORT bits_in_string; // bits inserted in the string during current operation
PUCHAR tmp_string;
PUCHAR tmp_data;
for (data_bits = 0, tmp_string = String + (StartBit / CHAR_SIZE), tmp_data = Data;
NumberOfBits > 0; data_bits += bits_in_string, StartBit += bits_in_string,
NumberOfBits -= bits_in_string ) {
data_bits_remaining = CHAR_SIZE - (data_bits % CHAR_SIZE);
string_bits_needed = CHAR_SIZE - (StartBit % CHAR_SIZE);
if (data_bits_remaining == CHAR_SIZE && string_bits_needed == CHAR_SIZE) {
*tmp_string++ = *tmp_data++;
bits_in_string = CHAR_SIZE;
} else if (data_bits_remaining == CHAR_SIZE) { /* string_bits_needed != CHAR */
*tmp_string++ &= (UCHAR)((0xff << string_bits_needed ) |
(*tmp_data >> (CHAR_SIZE - string_bits_needed)));
bits_in_string = string_bits_needed;
} else if (string_bits_needed == CHAR_SIZE) { /* data_bits_remaining != CHAR_SIZE */
*tmp_string &= (0xff >> data_bits_remaining) |
(*tmp_data++ << (CHAR_SIZE - data_bits_remaining));
bits_in_string = data_bits_remaining;
} else {
/*RMU this is an error case... */
}
}
}
VOID
NCRCatExtractData(
PUCHAR String,
SHORT StartBit,
PUCHAR Data,
SHORT NumberOfBits
)
/*++
Routine Description:
Function extract NumberBits of data from the string and places them in
the string Data.
Arguments:
Return Value:
--*/
{
SHORT data_bits; // running count of data bits in the data string
SHORT data_bits_needed; // data bits needed from to fill current char
SHORT string_bits_remaining; // string bits remaining in current char
SHORT bits_extracted; // bits extracted from the string with last operation
PUCHAR tmp_string;
PUCHAR tmp_data;
for (data_bits = 0, tmp_data = Data, (tmp_string = String + (StartBit / CHAR_SIZE));
NumberOfBits > 0; data_bits += bits_extracted, StartBit += bits_extracted,
NumberOfBits -= bits_extracted ) {
data_bits_needed = CHAR_SIZE - (data_bits % CHAR_SIZE);
string_bits_remaining = CHAR_SIZE - (StartBit % CHAR_SIZE);
if (string_bits_remaining == CHAR_SIZE && data_bits_needed == CHAR_SIZE) {
*tmp_data++ = *tmp_string;
bits_extracted = CHAR_SIZE;
}
else if (string_bits_remaining == CHAR_SIZE) { /* data_bits_needed != CHAR_SIZE */
*tmp_data++ |= *tmp_string >> (CHAR_SIZE - data_bits_needed);
bits_extracted = data_bits_needed;
}
else if (data_bits_needed == CHAR_SIZE) { /* string_bits_remaining != CHAR_SIZE */
*tmp_data |= *tmp_string++ << (CHAR_SIZE - string_bits_remaining);
bits_extracted = string_bits_remaining;
}
else {
/*RMU this is an error case ASSERT? */
}
}
}
LONG
NCRCatShiftOutData(
PUCHAR Data,
SHORT DataBytes,
SHORT HeaderBytes,
SHORT PadBits
)
/*++
Routine Description:
Function shifts out data starting with the last byte in the
data string (header is shifted out first). Also checks to make sure
the header shifted out matches the header shifted back in.
Arguments:
Return Value:
--*/
{
SHORT i;
SHORT start_bit;
UCHAR input = 0;
UCHAR header = 0;
for (i = DataBytes + HeaderBytes - 1; i >= HeaderBytes; i--) {
WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)*(Data + i));
}
for (i = HeaderBytes - 1; i >= 0; i--, header = 0) { /* check the header */
WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)*(Data + i));
input = READ_PORT_UCHAR((PUCHAR)NCRCatDataPort);
start_bit = ((DataBytes + i) * CHAR_SIZE) - PadBits;
NCRCatExtractData(Data, start_bit, &header, CHAR_SIZE);
if (input != header)
return (CATIO);
}
return (CATNOERR);
}
LONG
NCRCatGetData(
PASIC Asic,
PUCHAR Data,
LONG InternalRegister
)
/*++
Routine Description:
Functions writes 0xAA in the NCRCatDataPort to be shifted out. Then
the results of the shift are read from the NCRCatDataPort and placed in the
string "string". This loop continues until the requested data has been
placed in the string "string". Then the requested data is extracted from
the string "string" and placed in the "Data" string.
Arguments:
Return Value:
--*/
{
SHORT i;
SHORT string_bits;
SHORT string_bytes;
SHORT trailer_bytes;
SHORT pad_bits;
UCHAR string[MAX_SCAN_PATH];
UCHAR trailer[MAX_REG_SIZE];
UCHAR input;
LONG status = CATNOERR;
if (NCRCatModule->ScanPathConnected == FALSE) {
/*
* For external register and subaddress space, use the RUN command
* to generate extra clock cycles for data access.
*/
if (InternalRegister == FALSE) {
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
}
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)DRCYC);
WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)HEADER);
*Data = READ_PORT_UCHAR((PUCHAR)NCRCatDataPort);
WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)0xAA);
if (READ_PORT_UCHAR((PUCHAR)NCRCatDataPort) != HEADER)
status = CATIO;
return (status);
}
WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)DRCYC);
string_bits = NCRCatModule->NumberOfAsics - 1 + Asic->InstructionRegisterLength;
string_bytes = string_bits / CHAR_SIZE;
if (pad_bits = string_bits % CHAR_SIZE) {
pad_bits = CHAR_SIZE - pad_bits;
string_bytes++;
}
trailer_bytes = Asic->InstructionRegisterLength / CHAR_SIZE;
if (Asic->InstructionRegisterLength % CHAR_SIZE)
trailer_bytes++;
NCRCatBuildHeader((PUCHAR)(trailer), trailer_bytes, Asic->InstructionRegisterLength, 1);
/*
* Shift out the trailer while data is being shifted into the string.
*/
for (i = trailer_bytes - 1; i >= 0; i--) {
WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)*(trailer + i));
*(string + string_bytes + i) = READ_PORT_UCHAR((PUCHAR)NCRCatDataPort);
}
/*
* Shift out 0xAA until the trailer is shifted back into the string
*/
for (i = string_bytes - 1; i >= 0; i--) {
WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)0xAA);
*(string + i) = READ_PORT_UCHAR((PUCHAR)NCRCatDataPort);
}
*Data = 0;
NCRCatExtractData(string, (SHORT)(pad_bits + (trailer_bytes * CHAR_SIZE) +
Asic->AsicLocation), Data, Asic->InstructionRegisterLength);
for (i = 0; i < trailer_bytes; i++) {
input = 0;
NCRCatExtractData(string, (SHORT)(pad_bits + (CHAR_SIZE * i)), &input, CHAR_SIZE);
if (*(trailer + i) != input) {
status = CATIO;
break;
}
}
return (status);
}
LONG
NCRCatIoLpb(
PCAT_CONTROL CatControl,
PUCHAR Buffer
)
/*++
Routine Description:
The following code is for accessing the LPB EEprom image. Since the LPB
is not on the cat bus, we must map in this area before accessing it in
physical memory.
Arguments:
Return Value:
--*/
{
return (CATNOERR);
}
VOID
NCRCatModuleName (
LONG Module,
PUNICODE_STRING ModuleName
)
/*++
Routine Description:
Given a module ID return the module name.
Arguments:
Return Value:
--*/
{
NTSTATUS status;
switch (Module) {
case PROCESSOR0:
status = RtlAppendUnicodeToString(ModuleName, L"Processor 0");
break;
case PROCESSOR1:
status = RtlAppendUnicodeToString(ModuleName, L"Processor 1");
break;
case PROCESSOR2:
status = RtlAppendUnicodeToString(ModuleName, L"Processor 2");
break;
case PROCESSOR3:
status = RtlAppendUnicodeToString(ModuleName, L"Processor 3");
break;
case MEMORY0:
status = RtlAppendUnicodeToString(ModuleName, L"Memory 0");
break;
case MEMORY1:
status = RtlAppendUnicodeToString(ModuleName, L"Memory 1");
break;
case PRIMARYMC:
status = RtlAppendUnicodeToString(ModuleName, L"PrimaryMicroChannel");
break;
case SECONDARYMC:
status = RtlAppendUnicodeToString(ModuleName, L"SecondaryMicroChannel");
break;
case PSI:
status = RtlAppendUnicodeToString(ModuleName, L"PowerSupplyInterface");
break;
case CAT_LPB_MODULE:
status = RtlAppendUnicodeToString(ModuleName, L"LocalPeripheralBoard");
break;
default:
status = RtlIntegerToUnicodeString(Module, 16, ModuleName);
break;
}
}
PWSTR ProcessorAsicNames[16] = {
L"CAT_I",
L"A_PBC",
L"B_PBC",
L"3",
L"4",
L"5",
L"6",
L"CPU_CATI7",
L"8",
L"CPU_Config2",
L"A",
L"CPU_Config4",
L"CPU_Config5",
L"CPU_Config6",
L"CPU_Config7",
L"PBC_Status"
};
PWSTR MemoryAsicNames[7] = {
L"CAT_I",
L"MMC1",
L"MMA1",
L"MMD1_0",
L"MMD1_1",
L"MMD1_2",
L"MMD1_3"
};
PWSTR PMCAsicNames[9] = {
L"CAT_I",
L"PMC_MCADDR",
L"PMC_DMA",
L"PMC_DS1",
L"PMC_DS0",
L"PMC_VIC",
L"PMC_ARB",
L"PMC_DS2",
L"PMC_DS3",
};
PWSTR SMCAsicNames[9] = {
L"CAT_I",
L"PMC_MCADDR",
L"PMC_DMA",
L"PMC_DS1",
L"PMC_DS0",
L"5",
L"6",
L"PMC_DS2",
L"PMC_DS3",
};
VOID
NCRCatAsicName (
LONG Module,
LONG Asic,
PUNICODE_STRING AsicName
)
/*++
Routine Description:
Given a Module ID and an Asic ID return the Asic name.
Arguments:
Return Value:
--*/
{
NTSTATUS status;
switch (Module) {
case PROCESSOR0:
case PROCESSOR1:
case PROCESSOR2:
case PROCESSOR3:
if (Asic > PBC_Status) {
status = RtlIntegerToUnicodeString(Asic,
16, AsicName);
} else {
status = RtlAppendUnicodeToString( AsicName,
ProcessorAsicNames[Asic]);
}
break;
case MEMORY0:
case MEMORY1:
if (Asic > MMD1_3) {
status = RtlIntegerToUnicodeString(Asic,
16, AsicName);
} else {
status = RtlAppendUnicodeToString( AsicName,
MemoryAsicNames[Asic]);
}
break;
case PSI:
switch (Asic) {
case CAT_I:
status = RtlAppendUnicodeToString( AsicName,
L"CAT_I");
break;
default:
status = RtlIntegerToUnicodeString(Asic,
16, AsicName);
break;
}
break;
case PRIMARYMC:
if (Asic > PMC_DS3) {
status = RtlIntegerToUnicodeString(Asic,
16, AsicName);
} else {
status = RtlAppendUnicodeToString( AsicName,
PMCAsicNames[Asic]);
}
break;
case SECONDARYMC:
if (Asic > SMC_DS3) {
status = RtlIntegerToUnicodeString(Asic,
16, AsicName);
} else {
status = RtlAppendUnicodeToString( AsicName,
SMCAsicNames[Asic]);
}
break;
default:
status = RtlIntegerToUnicodeString(Asic, 16, AsicName);
break;
}
}
VOID
HalpCatReportModuleAsics (
PUNICODE_STRING UnicodeModule,
PMODULE Module
)
/*++
Routine Description:
Place information about module Asics into the registry.
Arguments:
Return Value:
--*/
{
PASIC asic;
UNICODE_STRING unicode_asics;
OBJECT_ATTRIBUTES asics_attributes;
WCHAR asics_buffer[256];
UNICODE_STRING unicode_asic;
OBJECT_ATTRIBUTES asic_attributes;
WCHAR asic_buffer[256];
UNICODE_STRING unicode_asic_id;
UNICODE_STRING unicode_name;
WCHAR name_buffer[256];
HANDLE asics_handle;
HANDLE asic_handle;
NTSTATUS status;
ULONG tmp;
/* Asics */
unicode_asics.Length = 0;
unicode_asics.MaximumLength=256;
unicode_asics.Buffer = asics_buffer;
RtlZeroMemory(unicode_asics.Buffer,unicode_asics.MaximumLength);
RtlCopyUnicodeString(&unicode_asics,UnicodeModule);
status = RtlAppendUnicodeToString(&unicode_asics,L"\\Asics");
InitializeObjectAttributes( &asics_attributes, &unicode_asics,
OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwCreateKey(&asics_handle, KEY_READ | KEY_WRITE, &asics_attributes, 0,
(PUNICODE_STRING)NULL, REG_OPTION_VOLATILE, NULL);
for (asic = Module->Asic; asic != NULL; asic = asic->Next) {
/* Asic directory */
unicode_asic.Length = 0;
unicode_asic.MaximumLength=256;
unicode_asic.Buffer = asic_buffer;
RtlZeroMemory(unicode_asic.Buffer,unicode_asic.MaximumLength);
RtlCopyUnicodeString(&unicode_asic,&unicode_asics);
status = RtlAppendUnicodeToString(&unicode_asic,L"\\");
unicode_name.Length = 0;
unicode_name.MaximumLength=256;
unicode_name.Buffer = name_buffer;
NCRCatAsicName(Module->ModuleAddress, asic->AsicId, &unicode_name);
status = RtlAppendUnicodeStringToString(&unicode_asic,&unicode_name);
InitializeObjectAttributes( &asic_attributes, &unicode_asic,
OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwCreateKey(&asic_handle, KEY_READ | KEY_WRITE, &asic_attributes, 0,
(PUNICODE_STRING)NULL, REG_OPTION_VOLATILE, NULL);
// Asic ID
RtlInitUnicodeString(&unicode_asic_id,L"ID");
tmp = asic->AsicId;
status = ZwSetValueKey(asic_handle, &unicode_asic_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
// Asic JtagId
RtlInitUnicodeString(&unicode_asic_id,L"JtagID");
tmp = *((PULONG)(&(asic->JtagId[0])));
status = ZwSetValueKey(asic_handle, &unicode_asic_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
// Asic Type
RtlInitUnicodeString(&unicode_asic_id,L"Type");
tmp = asic->AsicType;
status = ZwSetValueKey(asic_handle, &unicode_asic_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
// Asic Location
RtlInitUnicodeString(&unicode_asic_id,L"Location");
tmp = asic->AsicLocation;
status = ZwSetValueKey(asic_handle, &unicode_asic_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
RtlInitUnicodeString(&unicode_asic_id,L"InstructionRegisterLength");
tmp = asic->InstructionRegisterLength;
status = ZwSetValueKey(asic_handle, &unicode_asic_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
RtlInitUnicodeString(&unicode_asic_id,L"BitLocation");
tmp = asic->BitLocation;
status = ZwSetValueKey(asic_handle, &unicode_asic_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
RtlInitUnicodeString(&unicode_asic_id,L"SubaddressSpace");
tmp = asic->SubaddressSpace;
status = ZwSetValueKey(asic_handle, &unicode_asic_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
status = ZwClose(asic_handle);
}
status = ZwClose(asics_handle);
}
VOID
HalpCatReportModuleSubModules (
PUNICODE_STRING UnicodeModule,
PMODULE Module
)
/*++
Routine Description:
Place information about system modules into the registry.
Arguments:
Return Value:
--*/
{
PMODULE module;
UNICODE_STRING unicode_submodules;
OBJECT_ATTRIBUTES submodules_attributes;
WCHAR submodules_buffer[256];
UNICODE_STRING unicode_module;
OBJECT_ATTRIBUTES module_attributes;
WCHAR module_buffer[256];
UNICODE_STRING unicode_module_id;
UNICODE_STRING unicode_name;
WCHAR name_buffer[256];
HANDLE submodules_handle;
HANDLE module_handle;
NTSTATUS status;
ULONG tmp;
unicode_submodules.Length = 0;
unicode_submodules.MaximumLength=256;
unicode_submodules.Buffer = submodules_buffer;
RtlZeroMemory(unicode_submodules.Buffer,unicode_submodules.MaximumLength);
RtlCopyUnicodeString(&unicode_submodules,UnicodeModule);
status = RtlAppendUnicodeToString(&unicode_submodules,L"\\SubModules");
InitializeObjectAttributes( &submodules_attributes, &unicode_submodules,
OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwCreateKey(&submodules_handle, KEY_READ | KEY_WRITE, &submodules_attributes, 0,
(PUNICODE_STRING)NULL, REG_OPTION_VOLATILE, NULL);
for (module = Module->SubModules; module != NULL; module = module->Next) {
/* Module directory */
unicode_module.Length = 0;
unicode_module.MaximumLength=256;
unicode_module.Buffer = module_buffer;
RtlZeroMemory(unicode_module.Buffer,unicode_module.MaximumLength);
RtlCopyUnicodeString(&unicode_module,&unicode_submodules);
status = RtlAppendUnicodeToString(&unicode_module,L"\\");
unicode_name.Length = 0;
unicode_name.MaximumLength=256;
unicode_name.Buffer = name_buffer;
NCRCatModuleName(module->ModuleAddress,&unicode_name);
status = RtlAppendUnicodeStringToString(&unicode_module,&unicode_name);
InitializeObjectAttributes( &module_attributes, &unicode_module,
OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwCreateKey(&module_handle, KEY_READ | KEY_WRITE, &module_attributes, 0,
(PUNICODE_STRING)NULL, REG_OPTION_VOLATILE, NULL);
/* Module ID */
RtlInitUnicodeString(&unicode_module_id,L"ID");
tmp = module->ModuleAddress;
status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
// EEProm size
RtlInitUnicodeString(&unicode_module_id,L"EEpromSize");
tmp = module->EEpromSize;
status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
// Number of Asics
RtlInitUnicodeString(&unicode_module_id,L"NumberOfAsics");
tmp = module->NumberOfAsics;
status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
// InstructionBits
RtlInitUnicodeString(&unicode_module_id,L"InstructionBits");
tmp = module->InstructionBits;
status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
// LargestRegister
RtlInitUnicodeString(&unicode_module_id,L"LargestRegister");
tmp = module->LargestRegister;
status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
// Smallest Register
RtlInitUnicodeString(&unicode_module_id,L"SmallestRegister");
tmp = module->SmallestRegister;
status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
if (module->SubModules) {
HalpCatReportModuleSubModules(&unicode_module,module);
}
if (module->Asic) {
HalpCatReportModuleAsics(&unicode_module,module);
}
status = ZwClose(module_handle);
}
status = ZwClose(submodules_handle);
}
VOID
HalpCatReportSystemModules (
)
/*++
Routine Description:
Place information about system modules into the registry.
Arguments:
Return Value:
--*/
{
PMODULE module;
PASIC asic;
PWSTR catbus_path = L"\\Registry\\Machine\\Hardware\\DeviceMap\\CatBus";
PWSTR modules_path = L"\\Registry\\Machine\\Hardware\\DeviceMap\\CatBus\\Modules";
UNICODE_STRING unicode_catbus;
OBJECT_ATTRIBUTES catbus_attributes;
UNICODE_STRING unicode_catbus_id;
UNICODE_STRING unicode_modules;
OBJECT_ATTRIBUTES modules_attributes;
UNICODE_STRING unicode_module;
OBJECT_ATTRIBUTES module_attributes;
WCHAR module_buffer[256];
UNICODE_STRING unicode_module_id;
UNICODE_STRING unicode_name;
WCHAR name_buffer[256];
HANDLE catbus_handle;
HANDLE modules_handle;
HANDLE module_handle;
NTSTATUS status;
ULONG tmp;
/*
* CatBus
*/
RtlInitUnicodeString(&unicode_catbus,catbus_path);
InitializeObjectAttributes( &catbus_attributes, &unicode_catbus,
OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwCreateKey(&catbus_handle, KEY_READ | KEY_WRITE, &catbus_attributes, 0,
(PUNICODE_STRING)NULL, REG_OPTION_VOLATILE, NULL);
// NCR Hal Version Number
RtlInitUnicodeString(&unicode_catbus_id,L"HalVersion");
tmp = NCR_VERSION_NUMBER;
status = ZwSetValueKey(catbus_handle, &unicode_catbus_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
/*
* Modules
*/
RtlInitUnicodeString(&unicode_modules,modules_path);
InitializeObjectAttributes( &modules_attributes, &unicode_modules,
OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwCreateKey(&modules_handle, KEY_READ | KEY_WRITE, &modules_attributes, 0,
(PUNICODE_STRING)NULL, REG_OPTION_VOLATILE, NULL);
for (module = NCRCatModuleList; module != NULL; module = module->Next) {
/* Module directory */
unicode_module.Length = 0;
unicode_module.MaximumLength=256;
unicode_module.Buffer = module_buffer;
RtlZeroMemory(unicode_module.Buffer,unicode_module.MaximumLength);
RtlCopyUnicodeString(&unicode_module,&unicode_modules);
status = RtlAppendUnicodeToString(&unicode_module,L"\\");
unicode_name.Length = 0;
unicode_name.MaximumLength=256;
unicode_name.Buffer = name_buffer;
NCRCatModuleName(module->ModuleAddress,&unicode_name);
status = RtlAppendUnicodeStringToString(&unicode_module,&unicode_name);
InitializeObjectAttributes( &module_attributes, &unicode_module,
OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwCreateKey(&module_handle, KEY_READ | KEY_WRITE, &module_attributes, 0,
(PUNICODE_STRING)NULL, REG_OPTION_VOLATILE, NULL);
/* Module ID */
RtlInitUnicodeString(&unicode_module_id,L"ID");
tmp = module->ModuleAddress;
status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
// EEProm size
RtlInitUnicodeString(&unicode_module_id,L"EEpromSize");
tmp = module->EEpromSize;
status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
// Number of Asics
RtlInitUnicodeString(&unicode_module_id,L"NumberOfAsics");
tmp = module->NumberOfAsics;
status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
// InstructionBits
RtlInitUnicodeString(&unicode_module_id,L"InstructionBits");
tmp = module->InstructionBits;
status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
// LargestRegister
RtlInitUnicodeString(&unicode_module_id,L"LargestRegister");
tmp = module->LargestRegister;
status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
// Smallest Register
RtlInitUnicodeString(&unicode_module_id,L"SmallestRegister");
tmp = module->SmallestRegister;
status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
if (module->SubModules) {
//
// This is a Quad board
//
// Larc size
//
RtlInitUnicodeString(&unicode_module_id,L"LARCPages");
tmp = NCRLarcEnabledPages[module->ModuleAddress&0xf];
status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
HalpCatReportModuleSubModules(&unicode_module,module);
}
if (module->Asic) {
HalpCatReportModuleAsics(&unicode_module,module);
}
status = ZwClose(module_handle);
}
status = ZwClose(modules_handle);
status = ZwClose(catbus_handle);
}
VOID
HalpCatPowerOffSystem (
)
/*++
Routine Description:
Sends command to PSI to shut off the power to the system.
Arguments:
Return Value:
--*/
{
CAT_CONTROL cat_control;
UCHAR data;
cat_control.Module = PSI;
cat_control.Asic = CAT_I;
//
// check position of Front panel switch to see if we need to enable it
// if the switch is in the off position then enable it
//
cat_control.Command = READ_SUBADDR;
cat_control.Address = PSI_General_Ps_Status_L5;
cat_control.NumberOfBytes = 1;
HalCatBusIo(&cat_control, &data);
if (!(data & PSI_PowerSwitch_On)) {
cat_control.Command = WRITE_SUBADDR;
cat_control.Address = PSI_General_Ps_Status_L5;
cat_control.NumberOfBytes = 1;
data = PSI_Enable_FrontSwitch;
HalCatBusIo(&cat_control, &data);
}
cat_control.Command = WRITE_SUBADDR;
cat_control.Address = PSI_General_Ps_Status_L5;
cat_control.NumberOfBytes = 1;
data = PSI_Set_AlarmEnable;
HalCatBusIo(&cat_control, &data);
//
// Power down the machine
//
data = PSI_SoftwarePowerDown1;
HalCatBusIo(&cat_control, &data);
return;
}
VOID
HalPowerOffSystem (
BOOLEAN PowerOffSystem
)
/*++
Routine Description:
Set a flag so HalReturnToFirmware will poweroff instead of reboot.
Arguments:
Return Value:
--*/
{
NCRPowerOffSystem = PowerOffSystem;
}