3224 lines
67 KiB
C
3224 lines
67 KiB
C
/*++
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|