1957 lines
49 KiB
C
1957 lines
49 KiB
C
#if defined(JAZZ)
|
||
|
||
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
jxconfig.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the ARC firmware Configuration Query functions as
|
||
described in the Advanced Risc Computing Specification (Revision 1.00),
|
||
section 3.3.3.4, for a MIPS R3000 or R4000 Jazz system.
|
||
|
||
Author:
|
||
|
||
David M. Robinson (davidro) 13-June-1991
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "fwp.h"
|
||
#include "string.h"
|
||
#include "selftest.h"
|
||
extern ULONG end;
|
||
|
||
//
|
||
// Define the ARC pathname mnemonics.
|
||
//
|
||
|
||
PCHAR MnemonicTable[] = {
|
||
"arc",
|
||
"cpu",
|
||
"fpu",
|
||
"pic",
|
||
"pdc",
|
||
"sic",
|
||
"sdc",
|
||
"sc",
|
||
"eisa",
|
||
"tc",
|
||
"scsi",
|
||
"dti",
|
||
"multi",
|
||
"disk",
|
||
"tape",
|
||
"cdrom",
|
||
"worm",
|
||
"serial",
|
||
"net",
|
||
"video",
|
||
"par",
|
||
"point",
|
||
"key",
|
||
"audio",
|
||
"other",
|
||
"rdisk",
|
||
"fdisk",
|
||
"tape",
|
||
"modem",
|
||
"monitor",
|
||
"print",
|
||
"pointer",
|
||
"keyboard",
|
||
"term",
|
||
"other"
|
||
};
|
||
|
||
//
|
||
// Function prototypes.
|
||
//
|
||
|
||
ARC_STATUS
|
||
FwRestoreConfiguration (
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
FwConfigurationSetChecksum(
|
||
VOID
|
||
);
|
||
|
||
ULONG
|
||
FwZeroCompressLength (
|
||
IN ULONG DataLength,
|
||
IN PVOID ConfigurationData
|
||
);
|
||
|
||
ULONG
|
||
FwZeroCompress (
|
||
IN ULONG DataLength,
|
||
IN PVOID ConfigurationData,
|
||
OUT PVOID OutputBuffer
|
||
);
|
||
|
||
VOID
|
||
FwZeroDecompress (
|
||
IN PVOID InBuffer,
|
||
IN ULONG Index,
|
||
OUT PVOID ConfigurationData,
|
||
IN ULONG Length
|
||
);
|
||
|
||
//
|
||
// IdentifierIndex and DataIndex identify the next free locations in the
|
||
// configuration identifier and data areas. Configuration points to the
|
||
// allocated configuration area.
|
||
//
|
||
|
||
ULONG IdentifierIndex;
|
||
ULONG DataIndex;
|
||
ULONG EisaDataIndex;
|
||
PCONFIGURATION Configuration;
|
||
|
||
//
|
||
// Boolean to keep checksum status of the NVRAM.
|
||
//
|
||
|
||
BOOLEAN NvramValid = FALSE;
|
||
|
||
//
|
||
// External data.
|
||
//
|
||
|
||
extern MONITOR_CONFIGURATION_DATA DefaultMonitor;
|
||
|
||
|
||
VOID
|
||
FwConfigurationInitialize (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the configuration area in memory, and the
|
||
configuration routine addresses.
|
||
|
||
Note: This routine is called at phase 1 initialization and
|
||
at this time nothing is available.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PCONFIGURATION_COMPONENT Processor, Child;
|
||
ULONG ProcessorNumber;
|
||
CHAR CpuPath[10];
|
||
|
||
//
|
||
// Initialize the configuration routine addresses in the system
|
||
// parameter block.
|
||
//
|
||
|
||
(PARC_GET_CHILD_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetChildRoutine] =
|
||
FwGetChild;
|
||
(PARC_GET_PARENT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetParentRoutine] =
|
||
FwGetParent;
|
||
(PARC_GET_PEER_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetPeerRoutine] =
|
||
FwGetPeer;
|
||
(PARC_ADD_CHILD_ROUTINE)SYSTEM_BLOCK->FirmwareVector[AddChildRoutine] =
|
||
FwAddChild;
|
||
(PARC_DELETE_COMPONENT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[DeleteComponentRoutine] =
|
||
FwDeleteComponent;
|
||
(PARC_GET_COMPONENT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetComponentRoutine] =
|
||
FwGetComponent;
|
||
(PARC_GET_DATA_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetDataRoutine] =
|
||
FwGetConfigurationData;
|
||
(PARC_SAVE_CONFIGURATION_ROUTINE)SYSTEM_BLOCK->FirmwareVector[SaveConfigurationRoutine] =
|
||
FwSaveConfiguration;
|
||
|
||
//
|
||
// Allocate a region to store the volatile configuration database.
|
||
//
|
||
|
||
Configuration = (PCONFIGURATION)FwAllocatePool(sizeof(CONFIGURATION));
|
||
|
||
//
|
||
// Initialize other static data.
|
||
//
|
||
|
||
IdentifierIndex = 0;
|
||
DataIndex = 0;
|
||
EisaDataIndex = 0;
|
||
|
||
if (FwRestoreConfiguration() == ESUCCESS) {
|
||
|
||
//
|
||
// Delete processor components.
|
||
//
|
||
|
||
for (ProcessorNumber = 0; ProcessorNumber < 2 ; ProcessorNumber++ ) {
|
||
sprintf(CpuPath,"cpu(%1d)", ProcessorNumber);
|
||
Processor = FwGetComponent(CpuPath);
|
||
if ((Processor != NULL) && (Processor->Type == CentralProcessor)) {
|
||
while ((Child = FwGetChild(Processor)) != NULL) {
|
||
FwDeleteComponent(Child);
|
||
}
|
||
FwDeleteComponent(Processor);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Add the first processor.
|
||
//
|
||
|
||
JzAddProcessor(0);
|
||
|
||
#ifdef DUO
|
||
//
|
||
// Add the second processor
|
||
//
|
||
|
||
ExecuteOnProcessorB((PPROCESSOR_TASK_ROUTINE)JzAddProcessor,1);
|
||
#endif
|
||
|
||
FwSaveConfiguration();
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
PCONFIGURATION_COMPONENT
|
||
FwAddChild (
|
||
IN PCONFIGURATION_COMPONENT Component,
|
||
IN PCONFIGURATION_COMPONENT NewComponent,
|
||
IN PVOID ConfigurationData OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine adds a new component entry as a child of Component, including
|
||
an identifier string if the IdentifierLength field of NewComponent is
|
||
non-zero, and configuration data if the ConfigurationDataLength field of
|
||
NewComponent is non-zero and the ConfigurationData parameter is present.
|
||
If Component is NULL, the root component is being added.
|
||
|
||
Arguments:
|
||
|
||
Component - Supplies a pointer to a configuration component.
|
||
|
||
NewComponent - Supplies a pointer to a new configuration component
|
||
to be added as a child of Component.
|
||
|
||
ConfigurationData - Supplies an optional pointer to a configuration
|
||
data buffer.
|
||
|
||
Return Value:
|
||
|
||
Returns a pointer to the new configuration component entry. If the
|
||
create operation was unsuccessful, NULL is returned.
|
||
|
||
--*/
|
||
{
|
||
PCONFIGURATION_PACKET Packet;
|
||
PCONFIGURATION_PACKET ParentPacket;
|
||
ULONG Index;
|
||
PUCHAR String;
|
||
PUCHAR Data;
|
||
BOOLEAN Eisa;
|
||
ULONG DataLength;
|
||
|
||
//
|
||
// If Component is NULL and the new Class is system, the root component is
|
||
// being added, otherwise find the first free component entry.
|
||
//
|
||
|
||
if ((Component == NULL) && (NewComponent->Class == SystemClass)) {
|
||
|
||
Packet = &Configuration->Packet[0];
|
||
|
||
//
|
||
// TEMPTEMP If the root component is being added, clear all of the
|
||
// configuration area. This is a Hack, should be replaced by
|
||
// a good way to do this.
|
||
//
|
||
|
||
RtlZeroMemory(Configuration, sizeof(CONFIGURATION));
|
||
IdentifierIndex = 0;
|
||
DataIndex = 0;
|
||
EisaDataIndex = 0;
|
||
|
||
} else {
|
||
|
||
//
|
||
// If the configuration is not valid, return NULL.
|
||
//
|
||
|
||
if (!NvramValid) {
|
||
return(NULL);
|
||
}
|
||
|
||
Packet = &Configuration->Packet[1];
|
||
|
||
for ( Index = 1 ; Packet->Parent != NULL ; Index++ ) {
|
||
|
||
//
|
||
// If no more entries, return NULL. Since Index is 0 based
|
||
// subtract one from NUMBER_OF_ENTRIES for end check.
|
||
//
|
||
|
||
if (Index >= (NUMBER_OF_ENTRIES - 1)) {
|
||
return NULL;
|
||
}
|
||
|
||
Packet++;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Check to see if the parent component is the eisa bus.
|
||
//
|
||
|
||
if ((Component != NULL) && (Component->Type == EisaAdapter)) {
|
||
Eisa = TRUE;
|
||
} else {
|
||
Eisa = FALSE;
|
||
}
|
||
|
||
//
|
||
// If there is not enough space for the new identifier string or the
|
||
// configuration data, return NULL.
|
||
//
|
||
|
||
if (IdentifierIndex + NewComponent->IdentifierLength >= LENGTH_OF_IDENTIFIER) {
|
||
return(NULL);
|
||
}
|
||
|
||
if (Eisa) {
|
||
DataLength = FwZeroCompressLength(NewComponent->ConfigurationDataLength,
|
||
ConfigurationData);
|
||
|
||
if (EisaDataIndex + DataLength >= LENGTH_OF_EISA_DATA) {
|
||
return(NULL);
|
||
}
|
||
} else {
|
||
if (DataIndex + NewComponent->ConfigurationDataLength >= LENGTH_OF_DATA) {
|
||
return(NULL);
|
||
}
|
||
}
|
||
|
||
//
|
||
// There is space for everything. Fill in new configuration entry first.
|
||
//
|
||
|
||
Packet->Component.Class = NewComponent->Class;
|
||
Packet->Component.Type = NewComponent->Type;
|
||
Packet->Component.Flags = NewComponent->Flags;
|
||
Packet->Component.Version = NewComponent->Version;
|
||
Packet->Component.Revision = NewComponent->Revision;
|
||
Packet->Component.Key = NewComponent->Key;
|
||
Packet->Component.AffinityMask = 0xffffffff;
|
||
Packet->Component.IdentifierLength = NewComponent->IdentifierLength;
|
||
Packet->Component.Identifier = &Configuration->Identifier[IdentifierIndex];
|
||
|
||
//
|
||
// If Component is NULL, this is the root component so the parent is NULL,
|
||
// otherwise find the parent packet.
|
||
//
|
||
|
||
if (Component == NULL) {
|
||
ParentPacket = NULL;
|
||
} else {
|
||
ParentPacket = CONTAINING_RECORD(Component,
|
||
CONFIGURATION_PACKET,
|
||
Component);
|
||
}
|
||
|
||
//
|
||
// Only copy configuration data length if configuration data is supplied.
|
||
//
|
||
|
||
if (ConfigurationData != NULL) {
|
||
Packet->Component.ConfigurationDataLength =
|
||
NewComponent->ConfigurationDataLength;
|
||
} else {
|
||
Packet->Component.ConfigurationDataLength = 0;
|
||
}
|
||
|
||
Packet->Parent = ParentPacket;
|
||
|
||
Packet->Child = NULL;
|
||
|
||
//
|
||
// Add identifer string.
|
||
//
|
||
|
||
String = NewComponent->Identifier;
|
||
|
||
for ( Index = 0 ; Index < NewComponent->IdentifierLength ; Index++ ) {
|
||
Configuration->Identifier[IdentifierIndex++] = *String++;
|
||
}
|
||
|
||
//
|
||
// Make sure identifier is zero terminated, if not add one.
|
||
//
|
||
|
||
if (Configuration->Identifier[IdentifierIndex - 1] != 0) {
|
||
Configuration->Identifier[IdentifierIndex++] = 0;
|
||
Packet->Component.IdentifierLength += 1;
|
||
}
|
||
|
||
//
|
||
// Copy configuration data.
|
||
//
|
||
|
||
if (Eisa) {
|
||
Packet->ConfigurationData = &Configuration->EisaData[EisaDataIndex];
|
||
EisaDataIndex += FwZeroCompress(NewComponent->ConfigurationDataLength,
|
||
ConfigurationData,
|
||
&Configuration->EisaData[EisaDataIndex]);
|
||
} else {
|
||
Data = (PUCHAR)ConfigurationData;
|
||
Packet->ConfigurationData = &Configuration->Data[DataIndex];
|
||
for ( Index = 0 ; Index < NewComponent->ConfigurationDataLength ; Index++ ) {
|
||
Configuration->Data[DataIndex++] = *Data++;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Add the new component as the first child of Component, unless this is
|
||
// the root component.
|
||
//
|
||
|
||
if (Component == NULL) {
|
||
Packet->Peer = NULL;
|
||
} else {
|
||
Packet->Peer = ParentPacket->Child;
|
||
ParentPacket->Child = Packet;
|
||
}
|
||
|
||
return (&Packet->Component);
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
FwDeleteComponent (
|
||
IN PCONFIGURATION_COMPONENT Component
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function deletes a component entry. If the entry has one or more
|
||
children, an error is returned, otherwise the entry is deleted. Deleting
|
||
the entry will implicitly delete the identifier string and the configuration
|
||
data.
|
||
|
||
Note that no attempt is made to compress the entry, identifier, or the
|
||
configuration data areas after an entry is deleted, as doing so would
|
||
potentially invalidate outstanding pointers.
|
||
|
||
Arguments:
|
||
|
||
Component - Supplies a pointer to a configuration component.
|
||
|
||
Return Value:
|
||
|
||
Returns ESUCCESS if the entry was successfully deleted, otherwise one of
|
||
the following error codes is returned.
|
||
|
||
EINVAL Component is not a valid configuration component, or the
|
||
configuration is not valid.
|
||
|
||
EACCES Component has children, and cannot be freed until they
|
||
are deleted.
|
||
|
||
|
||
--*/
|
||
{
|
||
PCONFIGURATION_PACKET Packet;
|
||
PCONFIGURATION_PACKET SearchPacket;
|
||
|
||
if (!NvramValid || (Component == NULL)) {
|
||
return EINVAL;
|
||
}
|
||
|
||
Packet = CONTAINING_RECORD(Component,
|
||
CONFIGURATION_PACKET,
|
||
Component);
|
||
|
||
//
|
||
// If Component's Parent field is NULL, return EINVAL.
|
||
//
|
||
|
||
if (Packet->Parent == NULL) {
|
||
return EINVAL;
|
||
}
|
||
|
||
//
|
||
// If Component has children, return EACCES.
|
||
//
|
||
|
||
if (Packet->Child != NULL) {
|
||
return EACCES;
|
||
}
|
||
|
||
//
|
||
// Find the entry that points to Component, and point it to
|
||
// Component's peer. If this is Component's parent, update the child
|
||
// pointer, otherwise this is a peer and update the peer pointer.
|
||
//
|
||
|
||
SearchPacket = Packet->Parent;
|
||
|
||
if (SearchPacket->Child == Packet) {
|
||
SearchPacket->Child = Packet->Peer;
|
||
} else {
|
||
SearchPacket = SearchPacket->Child;
|
||
while (SearchPacket->Peer != Packet) {
|
||
SearchPacket = SearchPacket->Peer;
|
||
}
|
||
SearchPacket->Peer = Packet->Peer;
|
||
}
|
||
|
||
//
|
||
// Delete Component by zeroing the parent pointer.
|
||
//
|
||
|
||
Packet->Parent = NULL;
|
||
|
||
return ESUCCESS;
|
||
}
|
||
|
||
|
||
PCONFIGURATION_COMPONENT
|
||
FwGetComponent (
|
||
IN PCHAR Pathname
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine searches the configuration tree for the component that best
|
||
matches the Pathname string.
|
||
|
||
Arguments:
|
||
|
||
Pathname - Supplies a string containing the pathname to search.
|
||
|
||
Return Value:
|
||
|
||
Returns a pointer to the configuration component that best matches
|
||
pathname. The algorithm is to search for each component starting with
|
||
the first. When the string has been exhausted or no component matches the
|
||
current string section, then a pointer to the last successfully matched
|
||
component is returned. If the configuration information is not valid,
|
||
NULL is returned.
|
||
|
||
--*/
|
||
{
|
||
PCONFIGURATION_COMPONENT Component;
|
||
PCONFIGURATION_COMPONENT MatchComponent;
|
||
PCHAR PathString;
|
||
PCHAR MatchString;
|
||
PCHAR Token;
|
||
ULONG Key;
|
||
|
||
//
|
||
// If the configuration is not valid, return NULL.
|
||
//
|
||
|
||
if (!NvramValid) {
|
||
return(NULL);
|
||
}
|
||
|
||
PathString = Pathname;
|
||
|
||
//
|
||
// Get the the root component.
|
||
//
|
||
|
||
MatchComponent = FwGetChild(NULL);
|
||
|
||
//
|
||
// Repeat search for each new match component.
|
||
//
|
||
|
||
do {
|
||
|
||
//
|
||
// Get the first child of the current match component.
|
||
//
|
||
|
||
Component = FwGetChild( MatchComponent );
|
||
|
||
//
|
||
// Search each child of the current match component for the next match.
|
||
//
|
||
|
||
while ( Component != NULL ) {
|
||
|
||
//
|
||
// Reset Token to be the current position on the pathname.
|
||
//
|
||
|
||
Token = PathString;
|
||
|
||
MatchString = MnemonicTable[Component->Type];
|
||
|
||
//
|
||
// Compare strings.
|
||
//
|
||
|
||
while (*MatchString == tolower(*Token)) {
|
||
MatchString++;
|
||
Token++;
|
||
}
|
||
|
||
//
|
||
// Strings compare if the first mismatch is the terminator for
|
||
// each.
|
||
//
|
||
|
||
if ((*MatchString == 0) && (*Token == '(')) {
|
||
|
||
//
|
||
// Form key.
|
||
//
|
||
|
||
Key = 0;
|
||
Token++;
|
||
while ((*Token != ')') && (*Token != 0)) {
|
||
Key = (Key * 10) + *Token++ - '0';
|
||
}
|
||
|
||
//
|
||
// If the key matches the component matches, so update
|
||
// pointers and break.
|
||
//
|
||
|
||
if (Component->Key == Key) {
|
||
PathString = Token + 1;
|
||
MatchComponent = Component;
|
||
break;
|
||
}
|
||
}
|
||
|
||
NextPeer:
|
||
Component = FwGetPeer( Component );
|
||
}
|
||
|
||
} while ((Component != NULL) && (*PathString != 0));
|
||
|
||
return MatchComponent;
|
||
}
|
||
|
||
PCONFIGURATION_COMPONENT
|
||
FwGetChild (
|
||
IN PCONFIGURATION_COMPONENT Component OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns a pointer to the configuration component for the first child of
|
||
Component. If Component is NULL, a pointer to the root configuration
|
||
component is returned.
|
||
|
||
Arguments:
|
||
|
||
Component - Supplies an optional pointer to a configuration component.
|
||
|
||
Return Value:
|
||
|
||
Returns a pointer to the configuration component for the first child of
|
||
Component. If Component has no children, this pointer will be NULL. If
|
||
Component is NULL, a pointer to the root configuration component is
|
||
returned. If the configuration is not valid, NULL is returned.
|
||
|
||
--*/
|
||
{
|
||
PCONFIGURATION_PACKET Packet;
|
||
|
||
//
|
||
// If the configuration is not valid, return NULL.
|
||
//
|
||
|
||
if (!NvramValid) {
|
||
return(NULL);
|
||
}
|
||
|
||
|
||
if (Component == NULL) {
|
||
return &Configuration->Packet[0].Component;
|
||
} else {
|
||
Packet = CONTAINING_RECORD(Component,
|
||
CONFIGURATION_PACKET,
|
||
Component);
|
||
|
||
return &((PCONFIGURATION_PACKET)(Packet->Child))->Component;
|
||
}
|
||
}
|
||
|
||
|
||
PCONFIGURATION_COMPONENT
|
||
FwGetParent (
|
||
IN PCONFIGURATION_COMPONENT Component
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function returns the parent of the named component.
|
||
|
||
Arguments:
|
||
|
||
Component - Supplies a pointer to a configuration component.
|
||
|
||
Return Value:
|
||
|
||
Returns a pointer to the configuration component for the parent of
|
||
Component. If Component has no parent NULL is returned (this is only
|
||
true for the root configuration component). If the configuration is
|
||
not valid, NULL is returned.
|
||
|
||
--*/
|
||
{
|
||
PCONFIGURATION_PACKET Packet;
|
||
|
||
//
|
||
// If the configuration is not valid, return NULL.
|
||
//
|
||
|
||
if (!NvramValid) {
|
||
return(NULL);
|
||
}
|
||
|
||
Packet = CONTAINING_RECORD(Component,
|
||
CONFIGURATION_PACKET,
|
||
Component);
|
||
|
||
if (Packet->Parent == NULL) {
|
||
return NULL;
|
||
} else {
|
||
return &((PCONFIGURATION_PACKET)(Packet->Parent))->Component;
|
||
}
|
||
}
|
||
|
||
|
||
PCONFIGURATION_COMPONENT
|
||
FwGetPeer (
|
||
IN PCONFIGURATION_COMPONENT Component
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function returns the peer of the named component.
|
||
|
||
Arguments:
|
||
|
||
Component - Supplies a pointer to a configuration component.
|
||
|
||
Return Value:
|
||
|
||
Returns a pointer to the configuration component for the next peer of
|
||
Component. If Component has no next peer, NULL is returned. If the
|
||
configuration is not valid, NULL is returned.
|
||
|
||
--*/
|
||
{
|
||
PCONFIGURATION_PACKET Packet;
|
||
|
||
//
|
||
// If the configuration is not valid, return NULL.
|
||
//
|
||
|
||
if (!NvramValid) {
|
||
return(NULL);
|
||
}
|
||
|
||
Packet = CONTAINING_RECORD(Component,
|
||
CONFIGURATION_PACKET,
|
||
Component);
|
||
|
||
if (Packet->Peer == NULL) {
|
||
return NULL;
|
||
} else {
|
||
return &((PCONFIGURATION_PACKET)(Packet->Peer))->Component;
|
||
}
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
FwGetConfigurationDataIndex
|
||
(
|
||
OUT PVOID ConfigurationData,
|
||
IN PCONFIGURATION_COMPONENT Component,
|
||
IN ULONG Index,
|
||
IN ULONG Length
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This functions returns the specified configuration data
|
||
associated with Component in the buffer supplied by
|
||
ConfigurationData. The max length of the data is stored
|
||
in the Component structure.
|
||
|
||
Arguments:
|
||
|
||
ConfigurationData - Supplies a pointer to a buffer to receive the
|
||
configuration data.
|
||
|
||
Component - Supplies a pointer to a configuration component.
|
||
|
||
Index - Supplies an index within the configuration data.
|
||
|
||
Length - Supplies the number of bytes to read (see the
|
||
ConfigurationDataLength field within the Component for the max
|
||
value).
|
||
|
||
Return Value:
|
||
|
||
If the configuration data is successfully copied into the buffer
|
||
provided by ConfigurationData, ESUCCESS is returned. Otherwise one of
|
||
the following error codes is returned.
|
||
|
||
EINVAL Component is not a valid configuration component or the
|
||
other arguments are invalid or the configuration is
|
||
not valid.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCONFIGURATION_PACKET Packet;
|
||
ULONG DataSize;
|
||
PUCHAR SourceData;
|
||
PUCHAR DestinationData;
|
||
|
||
//
|
||
// If the configuration is not valid, return EINVAL.
|
||
//
|
||
|
||
if (!NvramValid) {
|
||
return(EINVAL);
|
||
}
|
||
|
||
DataSize = Component->ConfigurationDataLength;
|
||
|
||
//
|
||
// check the passing parameters
|
||
//
|
||
|
||
if ( DataSize == 0 || Index >= DataSize || DataSize - Index < Length ) {
|
||
return EINVAL;
|
||
}
|
||
|
||
Packet = CONTAINING_RECORD( Component, CONFIGURATION_PACKET, Component );
|
||
|
||
//
|
||
// If Component's Parent field is NULL, return EINVAL.
|
||
//
|
||
|
||
if (Packet->Parent == NULL) {
|
||
return EINVAL;
|
||
}
|
||
|
||
//
|
||
// If this is an eisa component, decompress the data, otherwise just copy it.
|
||
//
|
||
|
||
if (Packet->Parent->Component.Type == EisaAdapter) {
|
||
FwZeroDecompress(Packet->ConfigurationData,
|
||
Index,
|
||
ConfigurationData,
|
||
Length);
|
||
|
||
} else {
|
||
SourceData = (PUCHAR)Packet->ConfigurationData + Index;
|
||
DestinationData = ConfigurationData;
|
||
|
||
while ( Length-- )
|
||
{
|
||
*DestinationData++ = *SourceData++;
|
||
}
|
||
}
|
||
|
||
return ESUCCESS;
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
FwGetConfigurationData (
|
||
OUT PVOID ConfigurationData,
|
||
IN PCONFIGURATION_COMPONENT Component
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This functions returns the configuration data associated with Component
|
||
in the buffer supplied by ConfigurationData. The length of the data
|
||
is stored in the Component structure.
|
||
|
||
Arguments:
|
||
|
||
ConfigurationData - Supplies a pointer to a buffer to receive the
|
||
configuration data.
|
||
|
||
Component - Supplies a pointer to a configuration component.
|
||
|
||
Return Value:
|
||
|
||
If the configuration data is successfully copied into the buffer
|
||
provided by ConfigurationData, ESUCCESS is returned. Otherwise one of
|
||
the following error codes is returned.
|
||
|
||
EINVAL Component is not a valid configuration component, or the
|
||
configuration is invalid.
|
||
|
||
--*/
|
||
|
||
{
|
||
return(FwGetConfigurationDataIndex(ConfigurationData,
|
||
Component,
|
||
0,
|
||
Component->ConfigurationDataLength));
|
||
}
|
||
|
||
|
||
|
||
ARC_STATUS
|
||
FwSaveConfiguration (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine stores all of the configuration entries into NVRAM,
|
||
including the associated identifier strings and configuration data.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
Returns ESUCCESS if the save completed successfully, otherwise one of the
|
||
following error codes is returned.
|
||
|
||
ENOSPC Not enough space in the NVRAM to save all of the data.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG EntryIndex;
|
||
ULONG Index;
|
||
PCONFIGURATION_PACKET Packet;
|
||
PCONFIGURATION_COMPONENT Component;
|
||
PNV_CONFIGURATION NvConfiguration;
|
||
COMPRESSED_CONFIGURATION_PACKET CompressedPacket;
|
||
USHORT NvIdentifierIndex;
|
||
USHORT NvDataIndex;
|
||
USHORT NvEisaDataIndex;
|
||
PUCHAR CompressedChars, NvChars, Data;
|
||
|
||
NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
||
NvIdentifierIndex = 0;
|
||
NvDataIndex = 0;
|
||
NvEisaDataIndex = 0;
|
||
|
||
//
|
||
// Write each volatile packet into a compressed non-volatile packet,
|
||
// including the identifier string and the configuration data.
|
||
//
|
||
|
||
for ( EntryIndex = 0 ; EntryIndex < NUMBER_OF_ENTRIES ; EntryIndex++ ) {
|
||
|
||
//
|
||
// Get pointers to the volatile data.
|
||
//
|
||
|
||
Packet = (PCONFIGURATION_PACKET)&Configuration->Packet[EntryIndex];
|
||
Component = &Packet->Component;
|
||
|
||
//
|
||
// If this is not the root entry and the parent field is NULL, zero
|
||
// entry and skip to next.
|
||
//
|
||
|
||
if ((EntryIndex != 0) && (Packet->Parent == NULL)) {
|
||
NvChars = (PUCHAR)&NvConfiguration->Packet[EntryIndex];
|
||
for ( Index = 0 ;
|
||
Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) ;
|
||
Index++ ) {
|
||
WRITE_REGISTER_UCHAR( NvChars++, 0);
|
||
}
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Determine the parent and store as an index. Note that the index
|
||
// (Packet->Parent) is 1 based, to reserve the value 0 to mean no
|
||
// parent.
|
||
//
|
||
|
||
if (EntryIndex != 0) {
|
||
CompressedPacket.Parent =
|
||
(UCHAR)(Packet->Parent - &Configuration->Packet[0]) + 1;
|
||
} else {
|
||
CompressedPacket.Parent = 0;
|
||
}
|
||
|
||
//
|
||
// Fill in the rest of the fields. Version and ConfigurationDataLength will
|
||
// never be larger than USHORTS.
|
||
//
|
||
|
||
CompressedPacket.Class = (UCHAR)Component->Class;
|
||
CompressedPacket.Type = (UCHAR)Component->Type;
|
||
CompressedPacket.Version = (UCHAR)Component->Version;
|
||
CompressedPacket.Revision = (UCHAR)Component->Revision;
|
||
CompressedPacket.Key = Component->Key;
|
||
CompressedPacket.ConfigurationDataLength =
|
||
(USHORT)Component->ConfigurationDataLength;
|
||
CompressedPacket.ConfigurationData = 0;
|
||
|
||
//
|
||
// Make sure the top bit of the flag field is zero unless it's set
|
||
// to be eisa below.
|
||
//
|
||
|
||
CompressedPacket.Flags = *(PUCHAR)(&Component->Flags) & 0x7f;
|
||
|
||
//
|
||
// If the component has an identifier string, copy it to NVRAM,
|
||
// otherwise set the index to indicate no identifier.
|
||
//
|
||
|
||
if (Component->IdentifierLength != 0) {
|
||
CompressedPacket.Identifier = NvIdentifierIndex;
|
||
for ( Index = 0 ; Index < Component->IdentifierLength ; Index++ ) {
|
||
WRITE_REGISTER_UCHAR(
|
||
&NvConfiguration->Identifier[NvIdentifierIndex++],
|
||
Component->Identifier[Index]);
|
||
}
|
||
} else {
|
||
CompressedPacket.Identifier = NO_CONFIGURATION_IDENTIFIER;
|
||
}
|
||
|
||
//
|
||
// If the component has configuration data, copy it to NVRAM.
|
||
//
|
||
|
||
if (Component->ConfigurationDataLength != 0) {
|
||
|
||
//
|
||
// If the parent component is the eisa bus, copy until the end
|
||
// of the compressed data.
|
||
//
|
||
|
||
if (Packet->Parent->Component.Type == EisaAdapter) {
|
||
CompressedPacket.ConfigurationData = NvEisaDataIndex;
|
||
Data = (PUCHAR)Packet->ConfigurationData;
|
||
for ( Index = 0 ; TRUE ; Index++ ) {
|
||
WRITE_REGISTER_UCHAR( &NvConfiguration->EisaData[NvEisaDataIndex++],
|
||
*Data++);
|
||
|
||
//
|
||
// If we've written at least two bytes and the last two
|
||
// bytes were zero we're at the end.
|
||
//
|
||
|
||
if ((Index > 1) && (!*(Data - 1) && !*(Data - 2))) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Set a flag to make it easier to determine that this is an
|
||
// Eisa component.
|
||
//
|
||
|
||
CompressedPacket.Flags |= 0x80;
|
||
|
||
} else {
|
||
CompressedPacket.ConfigurationData = NvDataIndex;
|
||
Data = (PUCHAR)Packet->ConfigurationData;
|
||
for ( Index = 0 ; Index < Component->ConfigurationDataLength ; Index++ ) {
|
||
WRITE_REGISTER_UCHAR( &NvConfiguration->Data[NvDataIndex++],
|
||
*Data++);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Write compressed packet to NVRAM.
|
||
//
|
||
|
||
CompressedChars = (PUCHAR)&CompressedPacket;
|
||
NvChars = (PUCHAR)&NvConfiguration->Packet[EntryIndex];
|
||
|
||
for ( Index = 0 ;
|
||
Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) ;
|
||
Index++ ) {
|
||
WRITE_REGISTER_UCHAR( NvChars++, *CompressedChars++);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Zero the rest of the identifier and configuration data areas.
|
||
//
|
||
|
||
for ( Index = NvIdentifierIndex ; Index < LENGTH_OF_IDENTIFIER ; Index++ ) {
|
||
WRITE_REGISTER_UCHAR( &NvConfiguration->Identifier[Index], 0);
|
||
}
|
||
|
||
for ( Index = NvDataIndex ; Index < LENGTH_OF_DATA ; Index++ ) {
|
||
WRITE_REGISTER_UCHAR( &NvConfiguration->Data[Index] ,0);
|
||
}
|
||
|
||
for ( Index = NvEisaDataIndex ; Index < LENGTH_OF_EISA_DATA ; Index++ ) {
|
||
WRITE_REGISTER_UCHAR( &NvConfiguration->EisaData[Index] ,0);
|
||
}
|
||
|
||
//
|
||
// Write configuration data checksum.
|
||
//
|
||
|
||
FwConfigurationSetChecksum();
|
||
|
||
//
|
||
// Restore configuration information out of NVRAM. This acts to compress
|
||
// the identifier and configuration data areas if any deletes have been
|
||
// performed.
|
||
//
|
||
|
||
return FwRestoreConfiguration();
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
FwRestoreConfiguration (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine restores all of the configuration entries from NVRAM,
|
||
including the associated identifier strings and configuration data.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
Returns ESUCCESS if the restore completed successfully, otherwise one of
|
||
the following error codes is returned.
|
||
|
||
EIO Invalid NVRAM checksum.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG EntryIndex;
|
||
ULONG Index;
|
||
PCONFIGURATION_PACKET Packet;
|
||
PCONFIGURATION_COMPONENT Component;
|
||
PNV_CONFIGURATION NvConfiguration;
|
||
COMPRESSED_CONFIGURATION_PACKET CompressedPacket;
|
||
USHORT NvIdentifierIndex;
|
||
USHORT NvDataIndex;
|
||
USHORT NvEisaDataIndex;
|
||
PUCHAR CompressedChars, NvChars;
|
||
PCONFIGURATION_PACKET SearchPacket;
|
||
ULONG Long;
|
||
|
||
|
||
NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
||
NvIdentifierIndex = 0;
|
||
NvDataIndex = 0;
|
||
NvEisaDataIndex = 0;
|
||
IdentifierIndex = 0;
|
||
DataIndex = 0;
|
||
EisaDataIndex = 0;
|
||
|
||
//
|
||
// Check the checksum, return error if invalid.
|
||
//
|
||
|
||
if (FwConfigurationCheckChecksum() != ESUCCESS) {
|
||
return EIO;
|
||
}
|
||
|
||
//
|
||
// Clear the configuration area.
|
||
//
|
||
|
||
RtlZeroMemory(Configuration, sizeof(CONFIGURATION));
|
||
|
||
//
|
||
// Read each non-volatile compressed packet into a volatile packet,
|
||
// including the identifier string and the configuration data.
|
||
//
|
||
|
||
for ( EntryIndex = 0 ; EntryIndex < NUMBER_OF_ENTRIES ; EntryIndex++ ) {
|
||
|
||
//
|
||
// Read compressed packet from NVRAM.
|
||
//
|
||
|
||
CompressedChars = (PUCHAR)&CompressedPacket;
|
||
NvChars = (PUCHAR)&NvConfiguration->Packet[EntryIndex];
|
||
|
||
for ( Index = 0 ;
|
||
Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) ;
|
||
Index++ ) {
|
||
*CompressedChars++ = READ_REGISTER_UCHAR( NvChars++ );
|
||
}
|
||
|
||
//
|
||
// If this is not the root entry and the parent field is NULL,
|
||
// go to the next.
|
||
//
|
||
|
||
if ((EntryIndex != 0) && (CompressedPacket.Parent == 0)) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Get pointers to the volatile area.
|
||
//
|
||
|
||
Packet = (PCONFIGURATION_PACKET)&Configuration->Packet[EntryIndex];
|
||
Component = &Packet->Component;
|
||
|
||
//
|
||
// If not the root entry and the parent field is within range, fill
|
||
// in parent field (note that the parent index
|
||
// is 1 based, subtract 1 to get correct index). If the parent's child
|
||
// pointer is NULL, fill in with the current entry, otherwise follow
|
||
// the links and add the current entry as the last peer.
|
||
//
|
||
|
||
if ((EntryIndex != 0) && (CompressedPacket.Parent <= NUMBER_OF_ENTRIES)) {
|
||
Packet->Parent = &Configuration->Packet[CompressedPacket.Parent - 1];
|
||
SearchPacket = Packet->Parent;
|
||
|
||
if (SearchPacket->Child == NULL) {
|
||
SearchPacket->Child = Packet;
|
||
} else {
|
||
SearchPacket = SearchPacket->Child;
|
||
while ( SearchPacket->Peer != NULL ) {
|
||
SearchPacket = SearchPacket->Peer;
|
||
}
|
||
SearchPacket->Peer = Packet;
|
||
}
|
||
} else {
|
||
Packet->Parent = NULL;
|
||
}
|
||
|
||
//
|
||
// NULL current packet's child and peer pointers.
|
||
//
|
||
|
||
Packet->Child = NULL;
|
||
Packet->Peer = NULL;
|
||
|
||
//
|
||
// Fill in the rest of the fields.
|
||
//
|
||
|
||
Component->Class = (CONFIGURATION_CLASS)CompressedPacket.Class;
|
||
Component->Type = (CONFIGURATION_TYPE)CompressedPacket.Type;
|
||
Component->Flags.Failed = (CompressedPacket.Flags & 0x01) ? 1 : 0;
|
||
Component->Flags.ReadOnly = (CompressedPacket.Flags & 0x02) ? 1 : 0;
|
||
Component->Flags.Removable = (CompressedPacket.Flags & 0x04) ? 1 : 0;
|
||
Component->Flags.ConsoleIn = (CompressedPacket.Flags & 0x08) ? 1 : 0;
|
||
Component->Flags.ConsoleOut = (CompressedPacket.Flags & 0x10) ? 1 : 0;
|
||
Component->Flags.Input = (CompressedPacket.Flags & 0x20) ? 1 : 0;
|
||
Component->Flags.Output = (CompressedPacket.Flags & 0x40) ? 1 : 0;
|
||
Component->Version = (USHORT)CompressedPacket.Version;
|
||
Component->Revision = (USHORT)CompressedPacket.Revision;
|
||
Component->Key = CompressedPacket.Key;
|
||
Component->AffinityMask = 0xffffffff;
|
||
Component->ConfigurationDataLength =
|
||
(ULONG)CompressedPacket.ConfigurationDataLength;
|
||
|
||
//
|
||
// If the component has an identifier string, copy it to memory.
|
||
//
|
||
|
||
Index = 0;
|
||
|
||
if (CompressedPacket.Identifier != NO_CONFIGURATION_IDENTIFIER) {
|
||
Component->Identifier = &Configuration->Identifier[IdentifierIndex];
|
||
do {
|
||
Configuration->Identifier[IdentifierIndex++] =
|
||
READ_REGISTER_UCHAR(
|
||
&NvConfiguration->Identifier[NvIdentifierIndex] );
|
||
Index++;
|
||
} while ( READ_REGISTER_UCHAR(&NvConfiguration->Identifier[NvIdentifierIndex++] ) );
|
||
}
|
||
|
||
//
|
||
// Set identifier length field.
|
||
//
|
||
|
||
Component->IdentifierLength = Index;
|
||
|
||
//
|
||
// If the component has configuration data, copy it to memory.
|
||
//
|
||
|
||
if (Component->ConfigurationDataLength != 0) {
|
||
|
||
//
|
||
// If the eisa flag is set, only copy the compressed data.
|
||
//
|
||
|
||
if (CompressedPacket.Flags & 0x80) {
|
||
Packet->ConfigurationData = &Configuration->EisaData[EisaDataIndex];
|
||
for ( Index = 0 ; TRUE ; Index++ ) {
|
||
Configuration->EisaData[EisaDataIndex++] =
|
||
READ_REGISTER_UCHAR( &NvConfiguration->EisaData[NvEisaDataIndex++] );
|
||
|
||
//
|
||
// If at least two bytes have been written and the last
|
||
// two bytes are zero, we're at the end.
|
||
//
|
||
|
||
if ((Index > 1) &&
|
||
(!Configuration->EisaData[EisaDataIndex - 1] &
|
||
!Configuration->EisaData[EisaDataIndex - 2])) {
|
||
break;
|
||
}
|
||
}
|
||
} else {
|
||
Packet->ConfigurationData = &Configuration->Data[DataIndex];
|
||
for ( Index = 0 ; Index < Component->ConfigurationDataLength ; Index++ ) {
|
||
Configuration->Data[DataIndex++] =
|
||
READ_REGISTER_UCHAR( &NvConfiguration->Data[NvDataIndex++] );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return(ESUCCESS);
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
FwConfigurationCheckChecksum (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine checks the configuration checksum.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
If the checksum is good, ESUCCESS is returned, otherwise EIO is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
PUCHAR NvChars;
|
||
PNV_CONFIGURATION NvConfiguration;
|
||
ULONG Index;
|
||
ULONG Checksum1, Checksum2;
|
||
|
||
NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
||
|
||
//
|
||
// Form checksum from NVRAM data.
|
||
//
|
||
|
||
Checksum1 = 0;
|
||
NvChars = (PUCHAR)NvConfiguration;
|
||
|
||
for ( Index = 0 ;
|
||
Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) * NUMBER_OF_ENTRIES +
|
||
LENGTH_OF_IDENTIFIER + LENGTH_OF_DATA;
|
||
Index++ ) {
|
||
Checksum1 += READ_REGISTER_UCHAR( NvChars++ );
|
||
}
|
||
|
||
//
|
||
// Reconstitute checksum and return error if no compare.
|
||
//
|
||
|
||
Checksum2 = (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum1[0] ) |
|
||
(ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum1[1] ) << 8 |
|
||
(ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum1[2] ) << 16 |
|
||
(ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum1[3] ) << 24 ;
|
||
|
||
if (Checksum1 != Checksum2) {
|
||
NvramValid = FALSE;
|
||
return EIO;
|
||
}
|
||
|
||
//
|
||
// Repeat for the eisa data area.
|
||
//
|
||
|
||
Checksum1 = 0;
|
||
NvChars = (PUCHAR)NvConfiguration->EisaData;
|
||
|
||
for ( Index = 0 ;
|
||
Index < LENGTH_OF_EISA_DATA;
|
||
Index++ ) {
|
||
Checksum1 += READ_REGISTER_UCHAR( NvChars++ );
|
||
}
|
||
|
||
//
|
||
// Reconstitute checksum and return error if no compare.
|
||
//
|
||
|
||
Checksum2 = (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum3[0] ) |
|
||
(ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum3[1] ) << 8 |
|
||
(ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum3[2] ) << 16 |
|
||
(ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum3[3] ) << 24 ;
|
||
|
||
if (Checksum1 != Checksum2) {
|
||
NvramValid = FALSE;
|
||
return EIO;
|
||
}
|
||
|
||
NvramValid = TRUE;
|
||
return(ESUCCESS);
|
||
}
|
||
|
||
VOID
|
||
FwConfigurationSetChecksum (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets the configuration checksum.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PUCHAR NvChars;
|
||
PNV_CONFIGURATION NvConfiguration;
|
||
ULONG Index;
|
||
ULONG Checksum1;
|
||
|
||
NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
||
|
||
//
|
||
// Form checksum from NVRAM data.
|
||
//
|
||
|
||
Checksum1 = 0;
|
||
NvChars = (PUCHAR)NvConfiguration;
|
||
|
||
for ( Index = 0 ;
|
||
Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) * NUMBER_OF_ENTRIES +
|
||
LENGTH_OF_IDENTIFIER + LENGTH_OF_DATA;
|
||
Index++ ) {
|
||
Checksum1 += READ_REGISTER_UCHAR( NvChars++ );
|
||
}
|
||
|
||
//
|
||
// Set checksum.
|
||
//
|
||
|
||
WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum1[0], Checksum1);
|
||
WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum1[1], Checksum1 >> 8);
|
||
WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum1[2], Checksum1 >> 16);
|
||
WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum1[3], Checksum1 >> 24);
|
||
|
||
//
|
||
// Repeat for the eisa data area.
|
||
//
|
||
|
||
Checksum1 = 0;
|
||
NvChars = (PUCHAR)NvConfiguration->EisaData;
|
||
|
||
for ( Index = 0 ;
|
||
Index < LENGTH_OF_EISA_DATA;
|
||
Index++ ) {
|
||
Checksum1 += READ_REGISTER_UCHAR( NvChars++ );
|
||
}
|
||
|
||
//
|
||
// Set checksum.
|
||
//
|
||
|
||
WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum3[0], Checksum1);
|
||
WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum3[1], Checksum1 >> 8);
|
||
WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum3[2], Checksum1 >> 16);
|
||
WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum3[3], Checksum1 >> 24);
|
||
|
||
NvramValid = TRUE;
|
||
return;
|
||
|
||
}
|
||
|
||
ARC_STATUS
|
||
FwGetVideoData (
|
||
OUT PMONITOR_CONFIGURATION_DATA MonitorData
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine finds the video board and monitor configuration data in the
|
||
NVRAM. Normally this information would be accessed through
|
||
FwGetConfigurationData, but the initialization code needs the video
|
||
information before the firmware routines have been initialized. If no
|
||
monitor data is found, then default data is returned.
|
||
|
||
Arguments:
|
||
|
||
MonitorData - Supplies a pointer to a structure to receive the monitor
|
||
configuration data.
|
||
|
||
Return Value:
|
||
|
||
Returns ESUCCESS if data was found and restored, otherwise returns one of
|
||
the following error codes.
|
||
|
||
EIO Invalid NVRAM checksum.
|
||
|
||
ENODEV Monitor data not found.
|
||
|
||
Note that in any event valid data is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
ARC_STATUS Status;
|
||
ULONG EntryIndex;
|
||
ULONG Index;
|
||
COMPRESSED_CONFIGURATION_PACKET CompressedPacket;
|
||
PUCHAR CompressedChars;
|
||
PUCHAR NvChars;
|
||
PUCHAR Data;
|
||
PNV_CONFIGURATION NvConfiguration;
|
||
|
||
NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
||
|
||
//
|
||
// Check configuration checksum, return error if not valid.
|
||
//
|
||
|
||
if (FwConfigurationCheckChecksum() != ESUCCESS){
|
||
Status = EIO;
|
||
} else {
|
||
|
||
//
|
||
// Search the NVRAM configuration entries for the monitor, skip
|
||
// the root entry.
|
||
//
|
||
|
||
for ( EntryIndex = 1 ; EntryIndex < NUMBER_OF_ENTRIES ; EntryIndex++ ) {
|
||
|
||
//
|
||
// Read compressed packet from NVRAM.
|
||
//
|
||
|
||
CompressedChars = (PUCHAR)&CompressedPacket;
|
||
NvChars = (PUCHAR)&NvConfiguration->Packet[EntryIndex];
|
||
|
||
for ( Index = 0 ;
|
||
Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) ;
|
||
Index++ ) {
|
||
*CompressedChars++ = READ_REGISTER_UCHAR( NvChars++ );
|
||
}
|
||
|
||
//
|
||
// If the parent field is not Null, and the packet is class Peripheral,
|
||
// type Monitor, this is the display.
|
||
//
|
||
|
||
if ((CompressedPacket.Parent != 0) &&
|
||
(CompressedPacket.Class == PeripheralClass) &&
|
||
(CompressedPacket.Type == MonitorPeripheral)) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If we've fallen out of the loop the monitor was not found, return
|
||
// error.
|
||
//
|
||
|
||
if (EntryIndex == NUMBER_OF_ENTRIES) {
|
||
Status = ENODEV;
|
||
} else {
|
||
|
||
//
|
||
// If the configuration data length is the correct value, copy the data
|
||
// into the monitor data structure, otherwise return an error.
|
||
//
|
||
|
||
if (CompressedPacket.ConfigurationDataLength == sizeof(MONITOR_CONFIGURATION_DATA)) {
|
||
Data = (PUCHAR)MonitorData;
|
||
for ( DataIndex = CompressedPacket.ConfigurationData ;
|
||
DataIndex < (CompressedPacket.ConfigurationData +
|
||
CompressedPacket.ConfigurationDataLength) ;
|
||
DataIndex++ ) {
|
||
*Data++ = READ_REGISTER_UCHAR( &NvConfiguration->Data[DataIndex] );
|
||
}
|
||
Status = ESUCCESS;
|
||
} else {
|
||
Status = ENODEV;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (Status != ESUCCESS) {
|
||
MonitorData->HorizontalResolution = DefaultMonitor.HorizontalResolution;
|
||
MonitorData->HorizontalDisplayTime = DefaultMonitor.HorizontalDisplayTime;
|
||
MonitorData->HorizontalBackPorch = DefaultMonitor.HorizontalBackPorch;
|
||
MonitorData->HorizontalFrontPorch = DefaultMonitor.HorizontalFrontPorch;
|
||
MonitorData->HorizontalSync = DefaultMonitor.HorizontalSync;
|
||
MonitorData->VerticalResolution = DefaultMonitor.VerticalResolution;
|
||
MonitorData->VerticalBackPorch = DefaultMonitor.VerticalBackPorch;
|
||
MonitorData->VerticalFrontPorch = DefaultMonitor.VerticalFrontPorch;
|
||
MonitorData->VerticalSync = DefaultMonitor.VerticalSync;
|
||
MonitorData->HorizontalScreenSize = DefaultMonitor.HorizontalScreenSize;
|
||
MonitorData->VerticalScreenSize = DefaultMonitor.VerticalScreenSize;
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
VOID
|
||
FwSetVideoData (
|
||
IN PMONITOR_CONFIGURATION_DATA MonitorData
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine stores the monitor configuration data in the
|
||
NVRAM. Normally this information would be accessed through
|
||
FwAddChild, but this routine allows this data to be set before the
|
||
configuration routines have been initialized.
|
||
|
||
N.B. This routine assumes the NVRAM has already been checked by
|
||
FwGetVideoData and is valid.
|
||
|
||
Arguments:
|
||
|
||
MonitorData - Supplies a pointer to a structure containing the monitor
|
||
configuration data.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
ARC_STATUS Status;
|
||
ULONG EntryIndex;
|
||
ULONG Index;
|
||
COMPRESSED_CONFIGURATION_PACKET CompressedPacket;
|
||
PUCHAR CompressedChars;
|
||
PUCHAR NvChars;
|
||
PUCHAR Data;
|
||
PNV_CONFIGURATION NvConfiguration;
|
||
|
||
NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
||
|
||
//
|
||
// Search the NVRAM configuration entries for the monitor, skip
|
||
// the root entry.
|
||
//
|
||
|
||
for ( EntryIndex = 1 ; EntryIndex < NUMBER_OF_ENTRIES ; EntryIndex++ ) {
|
||
|
||
//
|
||
// Read compressed packet from NVRAM.
|
||
//
|
||
|
||
CompressedChars = (PUCHAR)&CompressedPacket;
|
||
NvChars = (PUCHAR)&NvConfiguration->Packet[EntryIndex];
|
||
|
||
for ( Index = 0 ;
|
||
Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) ;
|
||
Index++ ) {
|
||
*CompressedChars++ = READ_REGISTER_UCHAR( NvChars++ );
|
||
}
|
||
|
||
//
|
||
// If the parent field is not Null, and the packet is class Peripheral,
|
||
// type Monitor, this is the display.
|
||
//
|
||
|
||
if ((CompressedPacket.Parent != 0) &&
|
||
(CompressedPacket.Class == PeripheralClass) &&
|
||
(CompressedPacket.Type == MonitorPeripheral)) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Copy the data into the monitor data structure.
|
||
//
|
||
|
||
Data = (PUCHAR)MonitorData;
|
||
for ( DataIndex = CompressedPacket.ConfigurationData ;
|
||
DataIndex < (CompressedPacket.ConfigurationData +
|
||
CompressedPacket.ConfigurationDataLength) ;
|
||
DataIndex++ ) {
|
||
WRITE_REGISTER_UCHAR( &NvConfiguration->Data[DataIndex], *Data++);
|
||
}
|
||
|
||
//
|
||
// Fix the checksum.
|
||
//
|
||
|
||
FwConfigurationSetChecksum();
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
ULONG
|
||
FwZeroCompressLength (
|
||
IN ULONG DataLength,
|
||
IN PVOID ConfigurationData
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the compressed length of a configuration data sample.
|
||
|
||
Arguments:
|
||
|
||
DataLength - Supplies the uncompressed length of the data.
|
||
|
||
ConfigurationData - Supplies a pointer to the uncompressed configuration data.
|
||
|
||
Return Value:
|
||
|
||
Returns the compressed length of the configuration data.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Index;
|
||
ULONG CompressedLength;
|
||
ULONG Zero;
|
||
PUCHAR In;
|
||
|
||
CompressedLength = 2;
|
||
Zero = 0;
|
||
In = ConfigurationData;
|
||
|
||
for (Index = 0; Index < DataLength ; Index++ ) {
|
||
if (*In++) {
|
||
CompressedLength++;
|
||
Zero = 0;
|
||
} else {
|
||
if (Zero++) {
|
||
if (Zero == 0x100) {
|
||
Zero = 1;
|
||
CompressedLength += 2;
|
||
}
|
||
} else {
|
||
CompressedLength += 2;
|
||
}
|
||
}
|
||
}
|
||
return(CompressedLength);
|
||
}
|
||
|
||
|
||
ULONG
|
||
FwZeroCompress (
|
||
IN ULONG DataLength,
|
||
IN PVOID ConfigurationData,
|
||
OUT PVOID OutputBuffer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine compresses configuration data.
|
||
|
||
Arguments:
|
||
|
||
DataLength - Supplies the uncompressed length of the data.
|
||
|
||
ConfigurationData - Supplies a pointer to the uncompressed configuration data.
|
||
|
||
OutputBuffer - Supplies a pointer to the buffer to receive the compressed data.
|
||
|
||
Return Value:
|
||
|
||
Returns the compressed length of the configuration data.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Index;
|
||
ULONG CompressedLength;
|
||
ULONG Zero;
|
||
PUCHAR In, Out;
|
||
|
||
In = (PUCHAR)ConfigurationData;
|
||
Out = (PUCHAR)OutputBuffer;
|
||
CompressedLength = 2;
|
||
Zero = 0;
|
||
|
||
for (Index = 0; Index < DataLength ; Index++ ) {
|
||
if (*In) {
|
||
if (Zero) {
|
||
Out++;
|
||
Zero = 0;
|
||
}
|
||
*Out++ = *In;
|
||
CompressedLength++;
|
||
} else {
|
||
if (Zero++) {
|
||
if (Zero == 0x100) {
|
||
*Out++ = 0xFF;
|
||
*Out++ = 0;
|
||
*Out = 1;
|
||
Zero = 1;
|
||
CompressedLength += 2;
|
||
} else {
|
||
*Out += 1;
|
||
}
|
||
} else {
|
||
*Out++ = 0;
|
||
*Out = 1;
|
||
CompressedLength += 2;
|
||
}
|
||
}
|
||
In++;
|
||
}
|
||
|
||
if (Zero) {
|
||
Out++;
|
||
}
|
||
|
||
*Out++ = 0;
|
||
*Out = 0;
|
||
|
||
return(CompressedLength);
|
||
}
|
||
|
||
|
||
VOID
|
||
FwZeroDecompress (
|
||
IN PVOID InBuffer,
|
||
IN ULONG Index,
|
||
OUT PVOID ConfigurationData,
|
||
IN ULONG Length
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine compresses configuration data.
|
||
|
||
Arguments:
|
||
|
||
InBuffer - Supplies a pointer to the compressed configuration data.
|
||
|
||
Index - Supplies the index into the uncompressed data to start returning.
|
||
|
||
ConfigurationData - Supplies a pointer to the output buffer.
|
||
|
||
Length - Supplies the length of data to uncompress.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG DecompressedLength;
|
||
ULONG Zero;
|
||
PUCHAR In, Out;
|
||
UCHAR OutChar;
|
||
|
||
if (InBuffer == NULL) {
|
||
return;
|
||
}
|
||
|
||
In = (PUCHAR)InBuffer;
|
||
Out = (PUCHAR)ConfigurationData;
|
||
DecompressedLength = 0;
|
||
Zero = 0;
|
||
|
||
while (DecompressedLength++ < Index + Length) {
|
||
|
||
if (Zero) {
|
||
Zero--;
|
||
} else if (*In) {
|
||
OutChar = *In++;
|
||
} else {
|
||
OutChar = 0;
|
||
Zero = *(++In) - 1;
|
||
In++;
|
||
}
|
||
|
||
if (DecompressedLength > Index) {
|
||
*Out++ = OutChar;
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
#endif
|