You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1889 lines
59 KiB
1889 lines
59 KiB
/*++
|
|
|
|
Copyright (c) 1990, 1991 Microsoft Corporation
|
|
|
|
|
|
Module Name:
|
|
|
|
hwdetect.c
|
|
|
|
Abstract:
|
|
|
|
This is the main hardware detection module. Its main function is
|
|
to detect various system hardware and build a configuration tree.
|
|
|
|
N.B. The configuration built in the detection module will needs to
|
|
be adjusted later before we switch to FLAT mode. The is because
|
|
all the "POINTER" is a far pointer instead of a flat pointer.
|
|
|
|
Author:
|
|
|
|
Shie-Lin Tzong (shielint) 16-Jan-92
|
|
|
|
|
|
Environment:
|
|
|
|
Real mode.
|
|
|
|
Revision History:
|
|
|
|
Kenneth Ray (kenray) Jan-1998
|
|
- Add: get docking station info from PnP BIOS and add to firmware tree
|
|
|
|
--*/
|
|
|
|
#include "hwdetect.h"
|
|
typedef VOID (*PINTERFACE_REFERENCE)(PVOID Context);
|
|
typedef VOID (*PINTERFACE_DEREFERENCE)(PVOID Context);
|
|
typedef PVOID PDEVICE_OBJECT;
|
|
#include "pci.h"
|
|
#include <string.h>
|
|
#include "apm.h"
|
|
#include <ntapmsdk.h>
|
|
#include "pcibios.h"
|
|
#include "pcienum.h"
|
|
|
|
#if DBG
|
|
|
|
PUCHAR TypeName[] = {
|
|
"ArcSystem",
|
|
"CentralProcessor",
|
|
"FloatingPointProcessor",
|
|
"PrimaryICache",
|
|
"PrimaryDCache",
|
|
"SecondaryICache",
|
|
"SecondaryDCache",
|
|
"SecondaryCache",
|
|
"EisaAdapter",
|
|
"TcaAdapter",
|
|
"ScsiAdapter",
|
|
"DtiAdapter",
|
|
"MultifunctionAdapter",
|
|
"DiskController",
|
|
"TapeController",
|
|
"CdRomController",
|
|
"WormController",
|
|
"SerialController",
|
|
"NetworkController",
|
|
"DisplayController",
|
|
"ParallelController",
|
|
"PointerController",
|
|
"KeyboardController",
|
|
"AudioController",
|
|
"OtherController",
|
|
"DiskPeripheral",
|
|
"FloppyDiskPeripheral",
|
|
"TapePeripheral",
|
|
"ModemPeripheral",
|
|
"MonitorPeripheral",
|
|
"PrinterPeripheral",
|
|
"PointerPeripheral",
|
|
"KeyboardPeripheral",
|
|
"TerminalPeripheral",
|
|
"OtherPeripheral",
|
|
"LinePeripheral",
|
|
"NetworkPeripheral",
|
|
"SystemMemory",
|
|
"DockingInformation",
|
|
"RealModeIrqRoutingTable",
|
|
"RealModePCIEnumeration",
|
|
"MaximumType"
|
|
};
|
|
|
|
VOID
|
|
CheckConfigurationTree(
|
|
FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry
|
|
);
|
|
|
|
extern
|
|
USHORT
|
|
HwGetKey(
|
|
VOID
|
|
);
|
|
#endif
|
|
|
|
VOID
|
|
GetIrqFromEisaData(
|
|
FPFWCONFIGURATION_COMPONENT_DATA ControllerList,
|
|
CONFIGURATION_TYPE ControllerType
|
|
);
|
|
|
|
//
|
|
// HwBusType - defines the BUS type of the machine.
|
|
// This variable is used by detection code only.
|
|
//
|
|
|
|
USHORT HwBusType = 0;
|
|
|
|
//
|
|
// AdapterEntry is the Configuration_Component_data for the bus adapter
|
|
//
|
|
|
|
FPFWCONFIGURATION_COMPONENT_DATA AdapterEntry = NULL;
|
|
|
|
//
|
|
// FpRomBlock - A far pointer to our Rom Block
|
|
//
|
|
|
|
FPUCHAR FpRomBlock = NULL;
|
|
USHORT RomBlockLength = 0;
|
|
|
|
//
|
|
// HwEisaConfigurationData - A far pointer to the EISA configuration
|
|
// data on EISA machine.
|
|
//
|
|
|
|
FPUCHAR HwEisaConfigurationData = NULL;
|
|
ULONG HwEisaConfigurationSize = 0L;
|
|
|
|
//
|
|
// DisableSerialMice - A bit flags to indicate the comports whose serial
|
|
// mouse detection should be skipped.
|
|
//
|
|
|
|
USHORT DisableSerialMice = 0x0;
|
|
|
|
//
|
|
// FastDetect - A boolean value indicating if we should skip detection of
|
|
// unsupported devices or devices that are detected by NT proper
|
|
//
|
|
UCHAR FastDetect = 0x0;
|
|
|
|
//
|
|
// DisablePccardIrqScan - A boolean value indicating if we should skip
|
|
// detection of usable IRQs connected to pccard controllers
|
|
//
|
|
UCHAR DisablePccardIrqScan = 0;
|
|
|
|
//
|
|
// NoIRQRouting - Skip calling PCI BIOS to get IRQ routing options.
|
|
//
|
|
|
|
UCHAR NoIRQRouting = 0;
|
|
|
|
//
|
|
// PCIEnum - Enumerating the devices on the PCI Buses. Off by default.
|
|
//
|
|
|
|
UCHAR PCIEnum = 0;
|
|
|
|
//
|
|
// NoLegacy - Skip keyboard and all of the above.
|
|
//
|
|
|
|
UCHAR NoLegacy = 0;
|
|
|
|
//
|
|
// Internal references and definitions.
|
|
//
|
|
|
|
typedef enum _RELATIONSHIP_FLAGS {
|
|
Child,
|
|
Sibling,
|
|
Parent
|
|
} RELATIONSHIP_FLAGS;
|
|
|
|
|
|
VOID
|
|
HardwareDetection(
|
|
ULONG HeapStart,
|
|
ULONG HeapSize,
|
|
ULONG ConfigurationTree,
|
|
ULONG HeapUsed,
|
|
ULONG OptionString,
|
|
ULONG OptionStringLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Main entrypoint of the HW recognizer test. The routine builds
|
|
a configuration tree and leaves it in the hardware heap.
|
|
|
|
Arguments:
|
|
|
|
HeapStart - Supplies the starting address of the configuaration heap.
|
|
|
|
HeapSize - Supplies the size of the heap in byte.
|
|
|
|
ConfigurationTree - Supplies a 32 bit FLAT address of the variable to
|
|
receive the hardware configuration tree.
|
|
|
|
HeapUsed - Supplies a 32 bit FLAT address of the variable to receive
|
|
the actual heap size in used.
|
|
|
|
OptionString - Supplies a 32 bit FLAT address of load option string.
|
|
|
|
OptionStringLength - Supplies the length of the OptionString
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
FPFWCONFIGURATION_COMPONENT_DATA ConfigurationRoot;
|
|
FPFWCONFIGURATION_COMPONENT_DATA FirstCom = NULL, FirstLpt = NULL;
|
|
FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry;
|
|
FPFWCONFIGURATION_COMPONENT_DATA AcpiAdapterEntry = NULL;
|
|
FPFWCONFIGURATION_COMPONENT Component;
|
|
RELATIONSHIP_FLAGS NextRelationship;
|
|
CHAR Identifier[256];
|
|
USHORT BiosYear, BiosMonth, BiosDay;
|
|
PUCHAR MachineId;
|
|
USHORT Length, InitialLength, i, Count = 0;
|
|
USHORT PnPBiosLength, SMBIOSLength;
|
|
FPCHAR IdentifierString;
|
|
PMOUSE_INFORMATION MouseInfo = 0;
|
|
USHORT KeyboardId = 0;
|
|
ULONG VideoAdapterType = 0;
|
|
FPULONG BlConfigurationTree = NULL;
|
|
FPULONG BlHeapUsed = NULL;
|
|
FPCHAR BlOptions, EndOptions;
|
|
PUCHAR RomChain;
|
|
FPUCHAR FpRomChain = NULL, ConfigurationData, EndConfigurationData;
|
|
SHORT FreeSize;
|
|
FPHWPARTIAL_RESOURCE_DESCRIPTOR Descriptor;
|
|
FPHWRESOURCE_DESCRIPTOR_LIST DescriptorList;
|
|
PCI_REGISTRY_INFO PciEntry;
|
|
APM_REGISTRY_INFO ApmEntry;
|
|
ULONG nDevIt;
|
|
USHORT PCIDeviceCount = 0;
|
|
|
|
|
|
DOCKING_STATION_INFO DockInfo = { 0, 0, 0, FW_DOCKINFO_BIOS_NOT_CALLED };
|
|
FPPCI_IRQ_ROUTING_TABLE IrqRoutingTable;
|
|
|
|
//
|
|
// First initialize our hardware heap.
|
|
//
|
|
|
|
HwInitializeHeap(HeapStart, HeapSize);
|
|
|
|
MAKE_FP(BlConfigurationTree, ConfigurationTree);
|
|
MAKE_FP(BlHeapUsed, HeapUsed);
|
|
MAKE_FP(BlOptions, OptionString);
|
|
|
|
//
|
|
// Parse OptionString to look for various ntdetect options
|
|
//
|
|
if (BlOptions && OptionStringLength <= 0x1000L && OptionStringLength > 0L) {
|
|
EndOptions = BlOptions + OptionStringLength;
|
|
|
|
if (*EndOptions == '\0') {
|
|
|
|
if (_fstrstr(BlOptions, "NOIRQSCAN")) {
|
|
DisablePccardIrqScan = 1;
|
|
}
|
|
|
|
if (_fstrstr(BlOptions, "NOIRQROUTING")) {
|
|
NoIRQRouting = 1;
|
|
}
|
|
|
|
if (_fstrstr(BlOptions, "PCIENUM") ||
|
|
_fstrstr(BlOptions, "RDBUILD") ) {
|
|
PCIEnum = 1; // enable PCI enumeration
|
|
}
|
|
|
|
if (_fstrstr(BlOptions, "NOLEGACY")) {
|
|
DisableSerialMice = 0xffff;
|
|
FastDetect = 0x1;
|
|
NoLegacy = 1;
|
|
}
|
|
|
|
if (_fstrstr(BlOptions, "FASTDETECT")) {
|
|
DisableSerialMice = 0xffff;
|
|
FastDetect = 0x1;
|
|
} else {
|
|
do {
|
|
if (BlOptions = _fstrstr(BlOptions, "NOSERIALMICE")) {
|
|
BlOptions += strlen("NOSERIALMICE");
|
|
while ((*BlOptions == ' ') || (*BlOptions == ':') ||
|
|
(*BlOptions == '=')) {
|
|
BlOptions++;
|
|
}
|
|
|
|
if (*BlOptions == 'C' && BlOptions[1] == 'O' &&
|
|
BlOptions[2] == 'M') {
|
|
BlOptions += 3;
|
|
while (TRUE) {
|
|
while (*BlOptions != '\0' && (*BlOptions == ' ' ||
|
|
*BlOptions == ',' || *BlOptions == ';' ||
|
|
*BlOptions == '0')) {
|
|
BlOptions++;
|
|
}
|
|
if (*BlOptions >= '0' && *BlOptions <= '9') {
|
|
if (BlOptions[1] < '0' || BlOptions[1] > '9') {
|
|
DisableSerialMice |= 1 << (*BlOptions - '0');
|
|
BlOptions++;
|
|
} else {
|
|
BlOptions++;
|
|
while (*BlOptions && *BlOptions <= '9' &&
|
|
*BlOptions >= '0') {
|
|
BlOptions++;
|
|
}
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
DisableSerialMice = 0xffff;
|
|
break;
|
|
}
|
|
}
|
|
} while (BlOptions && *BlOptions && (BlOptions < EndOptions)); // double checking
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Determine bus type
|
|
//
|
|
|
|
if (HwIsEisaSystem()) {
|
|
HwBusType = MACHINE_TYPE_EISA;
|
|
} else {
|
|
HwBusType = MACHINE_TYPE_ISA;
|
|
}
|
|
|
|
//
|
|
// Allocate heap space for System component and initialize it.
|
|
// Also make the System component the root of configuration tree.
|
|
//
|
|
|
|
#if DBG
|
|
clrscrn ();
|
|
BlPrint("Detecting System Component ...\n");
|
|
#endif
|
|
|
|
ConfigurationRoot = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
|
|
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
|
|
Component = &ConfigurationRoot->ComponentEntry;
|
|
|
|
Component->Class = SystemClass;
|
|
Component->Type = MaximumType; // NOTE should be IsaCompatible
|
|
Component->Version = 0;
|
|
Component->Key = 0;
|
|
Component->AffinityMask = 0;
|
|
Component->ConfigurationDataLength = 0;
|
|
MachineId = "AT/AT COMPATIBLE";
|
|
if (MachineId) {
|
|
Length = strlen(MachineId) + 1;
|
|
IdentifierString = (FPCHAR)HwAllocateHeap(Length, FALSE);
|
|
_fstrcpy(IdentifierString, MachineId);
|
|
Component->Identifier = IdentifierString;
|
|
Component->IdentifierLength = Length;
|
|
} else {
|
|
Component->Identifier = 0;
|
|
Component->IdentifierLength = 0;
|
|
}
|
|
NextRelationship = Child;
|
|
PreviousEntry = ConfigurationRoot;
|
|
|
|
#if DBG
|
|
BlPrint("Reading BIOS date ...\n");
|
|
#endif
|
|
|
|
HwGetBiosDate (0xF0000, 0xFFFF, &BiosYear, &BiosMonth, &BiosDay);
|
|
|
|
#if DBG
|
|
BlPrint("Done reading BIOS date (%d/%d/%d)\n",
|
|
BiosMonth, BiosDay, BiosYear);
|
|
|
|
BlPrint("Detecting PCI Bus Component ...\n");
|
|
#endif
|
|
|
|
if (BiosYear > 1992 || (BiosYear == 1992 && BiosMonth >= 11) ) {
|
|
|
|
// Bios date valid for pci presence check..
|
|
HwGetPciSystemData((PVOID) &PciEntry, TRUE);
|
|
|
|
} else {
|
|
|
|
// Bios date not confirmed...
|
|
HwGetPciSystemData((PVOID) &PciEntry, FALSE);
|
|
}
|
|
|
|
// If this is a PCI machine, we may need to get the IRQ routing table...
|
|
//
|
|
if (PciEntry.NoBuses)
|
|
{
|
|
// Add a PCI BIOS entry under the multi function key.
|
|
// This will hold the irq routing table if it can be retrieved.
|
|
//
|
|
AdapterEntry = (FPFWCONFIGURATION_COMPONENT_DATA) HwAllocateHeap (
|
|
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
|
|
Component = &AdapterEntry->ComponentEntry;
|
|
Component->Class = AdapterClass;
|
|
Component->Type = MultiFunctionAdapter;
|
|
|
|
strcpy (Identifier, "PCI BIOS");
|
|
i = strlen(Identifier) + 1;
|
|
IdentifierString = (FPCHAR)HwAllocateHeap(i, FALSE);
|
|
_fstrcpy(IdentifierString, Identifier);
|
|
|
|
Component->Version = 0;
|
|
Component->Key = 0;
|
|
Component->AffinityMask = 0xffffffff;
|
|
Component->IdentifierLength = i;
|
|
Component->Identifier = IdentifierString;
|
|
|
|
//
|
|
// Add it to the tree
|
|
//
|
|
|
|
if (NextRelationship == Sibling) {
|
|
PreviousEntry->Sibling = AdapterEntry;
|
|
AdapterEntry->Parent = PreviousEntry->Parent;
|
|
} else {
|
|
PreviousEntry->Child = AdapterEntry;
|
|
AdapterEntry->Parent = PreviousEntry;
|
|
}
|
|
|
|
NextRelationship = Sibling;
|
|
PreviousEntry = AdapterEntry;
|
|
|
|
//
|
|
// Now deal with the IRQ routing table if we need to.
|
|
//
|
|
|
|
if (NoIRQRouting) {
|
|
#if DBG
|
|
BlPrint("\nSkipping calling PCI BIOS to get IRQ routing table...\n");
|
|
#endif
|
|
} else {
|
|
|
|
//
|
|
// Add RealMode IRQ Routing Table to the tree
|
|
//
|
|
#if DBG
|
|
BlPrint("\nCalling PCI BIOS to get IRQ Routing table...\n");
|
|
#endif // DBG
|
|
|
|
IrqRoutingTable = HwGetRealModeIrqRoutingTable();
|
|
if (IrqRoutingTable)
|
|
{
|
|
CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
|
|
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
|
|
strcpy (Identifier, "PCI Real-mode IRQ Routing Table");
|
|
i = strlen(Identifier) + 1;
|
|
IdentifierString = (FPCHAR)HwAllocateHeap(i, FALSE);
|
|
_fstrcpy(IdentifierString, Identifier);
|
|
|
|
Component = &CurrentEntry->ComponentEntry;
|
|
Component->Class = PeripheralClass;
|
|
Component->Type = RealModeIrqRoutingTable;
|
|
Component->Version = 0;
|
|
Component->Key = 0;
|
|
Component->AffinityMask = 0xffffffff;
|
|
Component->IdentifierLength = i;
|
|
Component->Identifier = IdentifierString;
|
|
|
|
Length = IrqRoutingTable->TableSize + DATA_HEADER_SIZE;
|
|
CurrentEntry->ConfigurationData =
|
|
(FPHWRESOURCE_DESCRIPTOR_LIST) HwAllocateHeap (Length, TRUE);
|
|
|
|
Component->ConfigurationDataLength = Length;
|
|
_fmemcpy((FPUCHAR) CurrentEntry->ConfigurationData + DATA_HEADER_SIZE,
|
|
IrqRoutingTable,
|
|
Length - DATA_HEADER_SIZE);
|
|
|
|
HwSetUpFreeFormDataHeader(
|
|
(FPHWRESOURCE_DESCRIPTOR_LIST) CurrentEntry->ConfigurationData,
|
|
0,
|
|
0,
|
|
0,
|
|
Length - DATA_HEADER_SIZE
|
|
);
|
|
|
|
//
|
|
// Add it to tree
|
|
//
|
|
|
|
AdapterEntry->Child = CurrentEntry;
|
|
CurrentEntry->Parent = AdapterEntry;
|
|
}
|
|
#if DBG
|
|
BlPrint("Getting IRQ Routing table from PCI BIOS complete...\n");
|
|
#endif // DBG
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add a registry entry for each PCI bus
|
|
//
|
|
|
|
for (i=0; i < PciEntry.NoBuses; i++) {
|
|
|
|
AdapterEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
|
|
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
|
|
|
|
Component = &AdapterEntry->ComponentEntry;
|
|
Component->Class = AdapterClass;
|
|
Component->Type = MultiFunctionAdapter;
|
|
|
|
strcpy (Identifier, "PCI");
|
|
Length = strlen(Identifier) + 1;
|
|
IdentifierString = (FPCHAR)HwAllocateHeap(Length, FALSE);
|
|
_fstrcpy(IdentifierString, Identifier);
|
|
|
|
Component->Version = 0;
|
|
Component->Key = 0;
|
|
Component->AffinityMask = 0xffffffff;
|
|
Component->IdentifierLength = Length;
|
|
Component->Identifier = IdentifierString;
|
|
|
|
AdapterEntry->ConfigurationData = NULL;
|
|
Component->ConfigurationDataLength = 0;
|
|
|
|
if (i == 0) {
|
|
//
|
|
// For the first PCI bus include the PCI_REGISTRY_INFO
|
|
//
|
|
|
|
Length = sizeof(PCI_REGISTRY_INFO) + DATA_HEADER_SIZE;
|
|
ConfigurationData = (FPUCHAR) HwAllocateHeap(Length, TRUE);
|
|
|
|
Component->ConfigurationDataLength = Length;
|
|
AdapterEntry->ConfigurationData = ConfigurationData;
|
|
|
|
_fmemcpy ( ((FPUCHAR) ConfigurationData+DATA_HEADER_SIZE),
|
|
(FPVOID) &PciEntry, sizeof (PCI_REGISTRY_INFO));
|
|
|
|
HwSetUpFreeFormDataHeader(
|
|
(FPHWRESOURCE_DESCRIPTOR_LIST) ConfigurationData,
|
|
0,
|
|
0,
|
|
0,
|
|
Length - DATA_HEADER_SIZE
|
|
);
|
|
}
|
|
|
|
//
|
|
// Add it to tree
|
|
//
|
|
|
|
if (NextRelationship == Sibling) {
|
|
PreviousEntry->Sibling = AdapterEntry;
|
|
AdapterEntry->Parent = PreviousEntry->Parent;
|
|
} else {
|
|
PreviousEntry->Child = AdapterEntry;
|
|
AdapterEntry->Parent = PreviousEntry;
|
|
}
|
|
|
|
NextRelationship = Sibling;
|
|
PreviousEntry = AdapterEntry;
|
|
}
|
|
|
|
#if DBG
|
|
BlPrint("Detecting PCI Bus Component completes ...\n");
|
|
#endif
|
|
|
|
//
|
|
// Enumerate the PCI Devices.
|
|
//
|
|
|
|
if (PCIEnum == 0 || PciEntry.NoBuses == 0) {
|
|
#if DBG
|
|
BlPrint("\nSkipping enumeration of PCI devices...\n");
|
|
#endif
|
|
} else {
|
|
//
|
|
// Enumerate PCI Devices
|
|
//
|
|
#if DBG
|
|
clrscrn ();
|
|
BlPrint("\nEnumerating PCI Devices...\n");
|
|
#endif // DBG
|
|
|
|
PciInit(&PciEntry);
|
|
|
|
//
|
|
// Count the devices
|
|
//
|
|
|
|
for (nDevIt = 0; (nDevIt = PciFindDevice(0, 0, nDevIt)) != 0;) {
|
|
PCIDeviceCount++;
|
|
}
|
|
|
|
#if DBG
|
|
BlPrint("Found %d PCI devices\n", PCIDeviceCount );
|
|
#endif
|
|
|
|
CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
|
|
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
|
|
strcpy (Identifier, "PCI Devices");
|
|
i = strlen(Identifier) + 1;
|
|
IdentifierString = (FPCHAR)HwAllocateHeap(i, FALSE);
|
|
_fstrcpy(IdentifierString, Identifier);
|
|
|
|
Component = &CurrentEntry->ComponentEntry;
|
|
Component->Class = PeripheralClass;
|
|
Component->Type = RealModePCIEnumeration;
|
|
Component->Version = 0;
|
|
Component->Key = 0;
|
|
Component->AffinityMask = 0xffffffff;
|
|
Component->IdentifierLength = i;
|
|
Component->Identifier = IdentifierString;
|
|
|
|
Length = (( sizeof( USHORT ) + sizeof( PCI_COMMON_CONFIG )) * PCIDeviceCount) + DATA_HEADER_SIZE;
|
|
CurrentEntry->ConfigurationData =
|
|
(FPHWRESOURCE_DESCRIPTOR_LIST) HwAllocateHeap (Length, TRUE);
|
|
|
|
#if DBG
|
|
if (CurrentEntry->ConfigurationData == NULL ) {
|
|
BlPrint("Failed to allocate %d bytes for PCI Devices\n", Length );
|
|
}
|
|
#endif
|
|
|
|
Component->ConfigurationDataLength = Length;
|
|
|
|
//
|
|
// Fill in Device Information
|
|
//
|
|
PCIDeviceCount = 0;
|
|
|
|
for (nDevIt = 0; (nDevIt = PciFindDevice(0, 0, nDevIt)) != 0;) {
|
|
FPUCHAR pCurrent;
|
|
PCI_COMMON_CONFIG config;
|
|
|
|
PciReadConfig(nDevIt, 0, (UCHAR*)&config, sizeof(config));
|
|
|
|
pCurrent = (FPUCHAR) CurrentEntry->ConfigurationData + DATA_HEADER_SIZE + ( PCIDeviceCount * ( sizeof( USHORT) + sizeof ( PCI_COMMON_CONFIG ) ) );
|
|
|
|
*(FPUSHORT)pCurrent = PCI_ITERATOR_TO_BUSDEVFUNC(nDevIt);
|
|
|
|
_fmemcpy(pCurrent + sizeof( USHORT ),
|
|
&config,
|
|
sizeof ( USHORT ) + sizeof ( PCI_COMMON_CONFIG ) );
|
|
#if DBG
|
|
{
|
|
USHORT x = (config.BaseClass << 8) + config.SubClass;
|
|
|
|
BlPrint("%d: %d.%d.%d: PCI\\VEN_%x&DEV_%x&SUBSYS_%x%x&REV_%x&CC_%x",
|
|
PCIDeviceCount,
|
|
PCI_ITERATOR_TO_BUS(nDevIt),
|
|
PCI_ITERATOR_TO_DEVICE(nDevIt),
|
|
PCI_ITERATOR_TO_FUNCTION(nDevIt),
|
|
config.VendorID,
|
|
config.DeviceID,
|
|
config.u.type0.SubSystemID,
|
|
config.u.type0.SubVendorID,
|
|
config.RevisionID,
|
|
x );
|
|
|
|
if ( (config.HeaderType & (~PCI_MULTIFUNCTION) ) == PCI_BRIDGE_TYPE) {
|
|
BlPrint(" Brdg %d->%d\n",
|
|
config.u.type1.PrimaryBus,
|
|
config.u.type1.SecondaryBus );
|
|
} else {
|
|
BlPrint("\n");
|
|
}
|
|
}
|
|
#endif
|
|
PCIDeviceCount++;
|
|
}
|
|
|
|
HwSetUpFreeFormDataHeader(
|
|
(FPHWRESOURCE_DESCRIPTOR_LIST) CurrentEntry->ConfigurationData,
|
|
0,
|
|
0,
|
|
0,
|
|
Length - DATA_HEADER_SIZE
|
|
);
|
|
|
|
//
|
|
// Add it to tree
|
|
//
|
|
|
|
AdapterEntry->Child = CurrentEntry;
|
|
CurrentEntry->Parent = AdapterEntry;
|
|
|
|
#if DBG
|
|
BlPrint("Enumerating PCI devices complete...\n");
|
|
while ( ! HwGetKey ());
|
|
clrscrn();
|
|
#endif // DBG
|
|
|
|
#if DBG
|
|
//
|
|
// Scan the PCI Bus via the bios
|
|
//
|
|
ScanPCIViaBIOS(&PciEntry);
|
|
#endif
|
|
|
|
}
|
|
|
|
if (!NoLegacy) {
|
|
#if DBG
|
|
BlPrint("Detecting APM Bus Component ...\n");
|
|
#endif
|
|
|
|
if (HwGetApmSystemData((PVOID) &ApmEntry)) {
|
|
AdapterEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
|
|
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
|
|
|
|
Component = &AdapterEntry->ComponentEntry;
|
|
Component->Class = AdapterClass;
|
|
Component->Type = MultiFunctionAdapter;
|
|
|
|
strcpy (Identifier, "APM");
|
|
Length = strlen(Identifier) + 1;
|
|
IdentifierString = (FPCHAR)HwAllocateHeap(Length, FALSE);
|
|
_fstrcpy(IdentifierString, Identifier);
|
|
|
|
Component->Version = 0;
|
|
Component->Key = 0;
|
|
Component->AffinityMask = 0xffffffff;
|
|
Component->IdentifierLength = Length;
|
|
Component->Identifier = IdentifierString;
|
|
|
|
AdapterEntry->ConfigurationData = NULL;
|
|
Component->ConfigurationDataLength = 0;
|
|
|
|
//
|
|
|
|
Length = sizeof(APM_REGISTRY_INFO) + DATA_HEADER_SIZE;
|
|
ConfigurationData = (FPUCHAR) HwAllocateHeap(Length, TRUE);
|
|
|
|
Component->ConfigurationDataLength = Length;
|
|
AdapterEntry->ConfigurationData = ConfigurationData;
|
|
|
|
_fmemcpy ( ((FPUCHAR) ConfigurationData+DATA_HEADER_SIZE),
|
|
(FPVOID) &ApmEntry, sizeof (APM_REGISTRY_INFO));
|
|
|
|
HwSetUpFreeFormDataHeader(
|
|
(FPHWRESOURCE_DESCRIPTOR_LIST) ConfigurationData,
|
|
0,
|
|
0,
|
|
0,
|
|
Length - DATA_HEADER_SIZE
|
|
);
|
|
|
|
//
|
|
// Add it to tree
|
|
//
|
|
|
|
if (NextRelationship == Sibling) {
|
|
PreviousEntry->Sibling = AdapterEntry;
|
|
AdapterEntry->Parent = PreviousEntry->Parent;
|
|
} else {
|
|
PreviousEntry->Child = AdapterEntry;
|
|
AdapterEntry->Parent = PreviousEntry;
|
|
}
|
|
|
|
NextRelationship = Sibling;
|
|
PreviousEntry = AdapterEntry;
|
|
}
|
|
#if DBG
|
|
BlPrint("APM Data collection complete...\n");
|
|
#endif // DBG
|
|
}
|
|
|
|
|
|
#if DBG
|
|
BlPrint("Detecting PnP BIOS Bus Component ...\n");
|
|
#endif
|
|
|
|
if (HwGetPnpBiosSystemData(&ConfigurationData,
|
|
&PnPBiosLength,
|
|
&SMBIOSLength,
|
|
&DockInfo)) {
|
|
AdapterEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
|
|
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
|
|
|
|
AdapterEntry->ConfigurationData = ConfigurationData;
|
|
Component = &AdapterEntry->ComponentEntry;
|
|
Component->ConfigurationDataLength = PnPBiosLength +
|
|
SMBIOSLength +
|
|
DATA_HEADER_SIZE +
|
|
sizeof(HWPARTIAL_RESOURCE_DESCRIPTOR);
|
|
|
|
Component->Class = AdapterClass;
|
|
Component->Type = MultiFunctionAdapter;
|
|
|
|
strcpy (Identifier, "PNP BIOS");
|
|
i = strlen(Identifier) + 1;
|
|
IdentifierString = (FPCHAR)HwAllocateHeap(i, FALSE);
|
|
_fstrcpy(IdentifierString, Identifier);
|
|
|
|
Component->Version = 0;
|
|
Component->Key = 0;
|
|
Component->AffinityMask = 0xffffffff;
|
|
Component->IdentifierLength = i;
|
|
Component->Identifier = IdentifierString;
|
|
|
|
HwSetUpFreeFormDataHeader(
|
|
(FPHWRESOURCE_DESCRIPTOR_LIST) ConfigurationData,
|
|
0,
|
|
1,
|
|
0,
|
|
PnPBiosLength
|
|
);
|
|
((FPHWRESOURCE_DESCRIPTOR_LIST)ConfigurationData)->Count = 2;
|
|
|
|
//
|
|
// Setup SMBIOS PartialDescriptor
|
|
Descriptor = (FPHWPARTIAL_RESOURCE_DESCRIPTOR)(ConfigurationData +
|
|
PnPBiosLength +
|
|
DATA_HEADER_SIZE);
|
|
Descriptor->Type = RESOURCE_DEVICE_DATA;
|
|
Descriptor->ShareDisposition = 0;
|
|
Descriptor->Flags = 0;
|
|
Descriptor->u.DeviceSpecificData.DataSize = SMBIOSLength;
|
|
Descriptor->u.DeviceSpecificData.Reserved1 = 0;
|
|
Descriptor->u.DeviceSpecificData.Reserved2 = 0;
|
|
|
|
|
|
//
|
|
// Add it to tree
|
|
//
|
|
|
|
if (NextRelationship == Sibling) {
|
|
PreviousEntry->Sibling = AdapterEntry;
|
|
AdapterEntry->Parent = PreviousEntry->Parent;
|
|
} else {
|
|
PreviousEntry->Child = AdapterEntry;
|
|
AdapterEntry->Parent = PreviousEntry;
|
|
}
|
|
|
|
NextRelationship = Sibling;
|
|
PreviousEntry = AdapterEntry;
|
|
|
|
//
|
|
// Add Docking Information to tree
|
|
//
|
|
|
|
CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
|
|
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
|
|
|
|
strcpy (Identifier, "Docking State Information");
|
|
i = strlen(Identifier) + 1;
|
|
IdentifierString = (FPCHAR)HwAllocateHeap(i, FALSE);
|
|
_fstrcpy(IdentifierString, Identifier);
|
|
|
|
Component = &CurrentEntry->ComponentEntry;
|
|
Component->Class = PeripheralClass;
|
|
Component->Type = DockingInformation;
|
|
Component->Version = 0;
|
|
Component->Key = 0;
|
|
Component->AffinityMask = 0xffffffff;
|
|
Component->IdentifierLength = i;
|
|
Component->Identifier = IdentifierString;
|
|
|
|
Length = sizeof (DockInfo) + DATA_HEADER_SIZE;
|
|
CurrentEntry->ConfigurationData =
|
|
(FPHWRESOURCE_DESCRIPTOR_LIST) HwAllocateHeap (Length, TRUE);
|
|
|
|
Component->ConfigurationDataLength = Length;
|
|
_fmemcpy((FPCHAR) CurrentEntry->ConfigurationData + DATA_HEADER_SIZE,
|
|
&DockInfo,
|
|
Length - DATA_HEADER_SIZE);
|
|
|
|
HwSetUpFreeFormDataHeader(
|
|
(FPHWRESOURCE_DESCRIPTOR_LIST) CurrentEntry->ConfigurationData,
|
|
0,
|
|
0,
|
|
0,
|
|
Length - DATA_HEADER_SIZE
|
|
);
|
|
|
|
AdapterEntry->Child = CurrentEntry;
|
|
CurrentEntry->Parent = AdapterEntry;
|
|
|
|
}
|
|
#if DBG
|
|
BlPrint("PnP BIOS Data collection complete...\n");
|
|
#endif // DBG
|
|
|
|
//
|
|
// Allocate heap space for Bus component and initialize it.
|
|
//
|
|
|
|
#if DBG
|
|
BlPrint("Detecting Bus/Adapter Component ...\n");
|
|
#endif
|
|
|
|
AdapterEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
|
|
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
|
|
|
|
Component = &AdapterEntry->ComponentEntry;
|
|
|
|
Component->Class = AdapterClass;
|
|
|
|
//
|
|
// The assumption here is that the machine has only one
|
|
// type of IO bus. If a machine has more than one types of
|
|
// IO buses, it will not use this detection code anyway.
|
|
//
|
|
|
|
if (HwBusType == MACHINE_TYPE_EISA) {
|
|
|
|
//
|
|
// Note We don't collect EISA config data here. Because we may
|
|
// exhaust the heap space. We will collect the data after all
|
|
// the other components are detected.
|
|
//
|
|
|
|
Component->Type = EisaAdapter;
|
|
strcpy(Identifier, "EISA");
|
|
AdapterEntry->ConfigurationData = NULL;
|
|
Component->ConfigurationDataLength = 0;
|
|
|
|
} else {
|
|
|
|
//
|
|
// If not EISA, it must be ISA
|
|
//
|
|
|
|
Component->Type = MultiFunctionAdapter;
|
|
strcpy(Identifier, "ISA");
|
|
}
|
|
Length = strlen(Identifier) + 1;
|
|
IdentifierString = (FPCHAR)HwAllocateHeap(Length, FALSE);
|
|
_fstrcpy(IdentifierString, Identifier);
|
|
Component->Version = 0;
|
|
Component->Key = 0;
|
|
Component->AffinityMask = 0xffffffff;
|
|
Component->IdentifierLength = Length;
|
|
Component->Identifier = IdentifierString;
|
|
|
|
//
|
|
// Make Adapter component System's child
|
|
//
|
|
|
|
if (NextRelationship == Sibling) {
|
|
PreviousEntry->Sibling = AdapterEntry;
|
|
AdapterEntry->Parent = PreviousEntry->Parent;
|
|
} else {
|
|
PreviousEntry->Child = AdapterEntry;
|
|
AdapterEntry->Parent = PreviousEntry;
|
|
}
|
|
NextRelationship = Child;
|
|
PreviousEntry = AdapterEntry;
|
|
|
|
//
|
|
// Collect BIOS information for ConfigurationRoot component.
|
|
// This step is done here because we need data collected in
|
|
// adapter component. The ConfigurationData is:
|
|
// HWRESOURCE_DESCRIPTOR_LIST header
|
|
// HWPARTIAL_RESOURCE_DESCRIPTOR for Parameter Table
|
|
// HWPARTIAL_RESOURCE_DESCRIPTOR for Rom Blocks.
|
|
// (Note DATA_HEADER_SIZE contains the size of the first partial
|
|
// descriptor already.)
|
|
//
|
|
|
|
#if DBG
|
|
BlPrint("Collecting Disk Geometry...\n");
|
|
#endif
|
|
|
|
GetInt13DriveParameters((PVOID)&RomChain, &Length);
|
|
InitialLength = (USHORT)(Length + RESERVED_ROM_BLOCK_LIST_SIZE + DATA_HEADER_SIZE +
|
|
sizeof(HWPARTIAL_RESOURCE_DESCRIPTOR));
|
|
ConfigurationData = (FPUCHAR)HwAllocateHeap(InitialLength, FALSE);
|
|
EndConfigurationData = ConfigurationData + DATA_HEADER_SIZE;
|
|
if (Length != 0) {
|
|
FpRomChain = EndConfigurationData;
|
|
_fmemcpy(FpRomChain, (FPVOID)RomChain, Length);
|
|
}
|
|
EndConfigurationData += (sizeof(HWPARTIAL_RESOURCE_DESCRIPTOR) +
|
|
Length);
|
|
HwSetUpFreeFormDataHeader((FPHWRESOURCE_DESCRIPTOR_LIST)ConfigurationData,
|
|
0,
|
|
0,
|
|
0,
|
|
Length
|
|
);
|
|
|
|
//
|
|
// Scan ROM to collect all the ROM blocks, if possible.
|
|
//
|
|
|
|
#if DBG
|
|
BlPrint("Detecting ROM Blocks...\n");
|
|
#endif
|
|
|
|
FpRomBlock = EndConfigurationData;
|
|
GetRomBlocks(FpRomBlock, &Length);
|
|
RomBlockLength = Length;
|
|
if (Length != 0) {
|
|
EndConfigurationData += Length;
|
|
} else {
|
|
FpRomBlock = NULL;
|
|
}
|
|
|
|
//
|
|
// We have both RomChain and RomBlock information/Headers.
|
|
//
|
|
|
|
DescriptorList = (FPHWRESOURCE_DESCRIPTOR_LIST)ConfigurationData;
|
|
DescriptorList->Count = 2;
|
|
Descriptor = (FPHWPARTIAL_RESOURCE_DESCRIPTOR)(
|
|
EndConfigurationData - Length -
|
|
sizeof(HWPARTIAL_RESOURCE_DESCRIPTOR));
|
|
Descriptor->Type = RESOURCE_DEVICE_DATA;
|
|
Descriptor->ShareDisposition = 0;
|
|
Descriptor->Flags = 0;
|
|
Descriptor->u.DeviceSpecificData.DataSize = (ULONG)Length;
|
|
Descriptor->u.DeviceSpecificData.Reserved1 = 0;
|
|
Descriptor->u.DeviceSpecificData.Reserved2 = 0;
|
|
|
|
Length = (USHORT)(MAKE_FLAT_ADDRESS(EndConfigurationData) -
|
|
MAKE_FLAT_ADDRESS(ConfigurationData));
|
|
ConfigurationRoot->ComponentEntry.ConfigurationDataLength = Length;
|
|
ConfigurationRoot->ConfigurationData = ConfigurationData;
|
|
FreeSize = InitialLength - Length;
|
|
|
|
HwFreeHeap((ULONG)FreeSize);
|
|
|
|
//
|
|
// Set up device information structure for Keyboard.
|
|
//
|
|
|
|
#if DBG
|
|
BlPrint("Detecting Keyboard Component ...\n");
|
|
#endif
|
|
if (NoLegacy) {
|
|
//
|
|
// Do not touch the hardware because there may not be a ports 60/64 on
|
|
// the machine and we will hang if we try to touch them
|
|
//
|
|
KeyboardId = UNKNOWN_KEYBOARD;
|
|
}
|
|
else {
|
|
//
|
|
// Touch the hardware to try to determine an ID
|
|
//
|
|
KeyboardId = GetKeyboardId();
|
|
}
|
|
|
|
CurrentEntry = SetKeyboardConfigurationData(KeyboardId);
|
|
|
|
//
|
|
// Make display component the child of Adapter component.
|
|
//
|
|
|
|
if (NextRelationship == Sibling) {
|
|
PreviousEntry->Sibling = CurrentEntry;
|
|
CurrentEntry->Parent = PreviousEntry->Parent;
|
|
} else {
|
|
PreviousEntry->Child = CurrentEntry;
|
|
CurrentEntry->Parent = PreviousEntry;
|
|
}
|
|
NextRelationship = Sibling;
|
|
PreviousEntry = CurrentEntry;
|
|
|
|
if (!NoLegacy) {
|
|
//
|
|
// Set up device information for com port (Each COM component
|
|
// is treated as a controller class.)
|
|
//
|
|
|
|
#if DBG
|
|
BlPrint("Detecting ComPort Component ...\n");
|
|
#endif
|
|
|
|
if (CurrentEntry = GetComportInformation()) {
|
|
|
|
FirstCom = CurrentEntry;
|
|
|
|
//
|
|
// Make current component the child of Adapter component.
|
|
//
|
|
|
|
if (NextRelationship == Sibling) {
|
|
PreviousEntry->Sibling = CurrentEntry;
|
|
} else {
|
|
PreviousEntry->Child = CurrentEntry;
|
|
}
|
|
while (CurrentEntry) {
|
|
CurrentEntry->Parent = AdapterEntry;
|
|
PreviousEntry = CurrentEntry;
|
|
CurrentEntry = CurrentEntry->Sibling;
|
|
}
|
|
NextRelationship = Sibling;
|
|
}
|
|
|
|
//
|
|
// Set up device information for parallel port. (Each parallel
|
|
// is treated as a controller class.)
|
|
//
|
|
|
|
#if DBG
|
|
BlPrint("Detecting Parallel Component ...\n");
|
|
#endif
|
|
|
|
if (CurrentEntry = GetLptInformation()) {
|
|
|
|
FirstLpt = CurrentEntry;
|
|
|
|
//
|
|
// Make current component the child of Adapter component.
|
|
//
|
|
|
|
if (NextRelationship == Sibling) {
|
|
PreviousEntry->Sibling = CurrentEntry;
|
|
CurrentEntry->Parent = PreviousEntry->Parent;
|
|
} else {
|
|
PreviousEntry->Child = CurrentEntry;
|
|
CurrentEntry->Parent = PreviousEntry;
|
|
}
|
|
PreviousEntry = CurrentEntry;
|
|
CurrentEntry = CurrentEntry->Sibling;
|
|
while (CurrentEntry) {
|
|
CurrentEntry->Parent = PreviousEntry->Parent;
|
|
PreviousEntry = CurrentEntry;
|
|
CurrentEntry = CurrentEntry->Sibling;
|
|
}
|
|
NextRelationship = Sibling;
|
|
}
|
|
|
|
//
|
|
// Set up device information structure for Mouse.
|
|
//
|
|
|
|
#if DBG
|
|
BlPrint("Detecting Mouse Component ...\n");
|
|
#endif
|
|
|
|
if (CurrentEntry = GetMouseInformation()) {
|
|
|
|
//
|
|
// Make current component the child of Adapter component.
|
|
//
|
|
|
|
if (NextRelationship == Sibling) {
|
|
PreviousEntry->Sibling = CurrentEntry;
|
|
CurrentEntry->Parent = PreviousEntry->Parent;
|
|
} else {
|
|
PreviousEntry->Child = CurrentEntry;
|
|
CurrentEntry->Parent = PreviousEntry;
|
|
}
|
|
PreviousEntry = CurrentEntry;
|
|
CurrentEntry = CurrentEntry->Sibling;
|
|
while (CurrentEntry) {
|
|
CurrentEntry->Parent = PreviousEntry->Parent;
|
|
PreviousEntry = CurrentEntry;
|
|
CurrentEntry = CurrentEntry->Sibling;
|
|
}
|
|
NextRelationship = Sibling;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set up device information for floppy drives. (The returned information
|
|
// is a tree structure.)
|
|
//
|
|
|
|
#if DBG
|
|
BlPrint("Detecting Floppy Component ...\n");
|
|
#endif
|
|
|
|
if (CurrentEntry = GetFloppyInformation()) {
|
|
|
|
//
|
|
// Make current component the child of Adapter component.
|
|
//
|
|
|
|
if (NextRelationship == Sibling) {
|
|
PreviousEntry->Sibling = CurrentEntry;
|
|
} else {
|
|
PreviousEntry->Child = CurrentEntry;
|
|
}
|
|
while (CurrentEntry) {
|
|
CurrentEntry->Parent = AdapterEntry;
|
|
PreviousEntry = CurrentEntry;
|
|
CurrentEntry = CurrentEntry->Sibling;
|
|
}
|
|
NextRelationship = Sibling;
|
|
}
|
|
|
|
#if DBG
|
|
BlPrint("Detecting PcCard ISA IRQ mapping ...\n");
|
|
#endif
|
|
if (CurrentEntry = GetPcCardInformation()) {
|
|
//
|
|
// Make current component the child of Adapter component.
|
|
//
|
|
|
|
if (NextRelationship == Sibling) {
|
|
PreviousEntry->Sibling = CurrentEntry;
|
|
CurrentEntry->Parent = PreviousEntry->Parent;
|
|
} else {
|
|
PreviousEntry->Child = CurrentEntry;
|
|
CurrentEntry->Parent = PreviousEntry;
|
|
}
|
|
PreviousEntry = CurrentEntry;
|
|
CurrentEntry = CurrentEntry->Sibling;
|
|
while (CurrentEntry) {
|
|
CurrentEntry->Parent = PreviousEntry->Parent;
|
|
PreviousEntry = CurrentEntry;
|
|
CurrentEntry = CurrentEntry->Sibling;
|
|
}
|
|
NextRelationship = Sibling;
|
|
}
|
|
|
|
#if DBG
|
|
BlPrint("Detecting ACPI Bus Component ...\n");
|
|
#endif
|
|
|
|
if (HwGetAcpiBiosData(&ConfigurationData, &Length)) {
|
|
AcpiAdapterEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
|
|
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
|
|
|
|
AcpiAdapterEntry->ConfigurationData = ConfigurationData;
|
|
Component = &AcpiAdapterEntry->ComponentEntry;
|
|
Component->ConfigurationDataLength = Length;
|
|
|
|
Component->Class = AdapterClass;
|
|
Component->Type = MultiFunctionAdapter;
|
|
|
|
strcpy (Identifier, "ACPI BIOS");
|
|
i = strlen(Identifier) + 1;
|
|
IdentifierString = (FPCHAR)HwAllocateHeap(i, FALSE);
|
|
_fstrcpy(IdentifierString, Identifier);
|
|
|
|
Component->Version = 0;
|
|
Component->Key = 0;
|
|
Component->AffinityMask = 0xffffffff;
|
|
Component->IdentifierLength = i;
|
|
Component->Identifier = IdentifierString;
|
|
|
|
HwSetUpFreeFormDataHeader(
|
|
(FPHWRESOURCE_DESCRIPTOR_LIST) ConfigurationData,
|
|
0,
|
|
0,
|
|
0,
|
|
Length - DATA_HEADER_SIZE
|
|
);
|
|
|
|
//
|
|
// Add it to tree
|
|
//
|
|
// Big hack here. This code inserts the ACPI node in
|
|
// the tree one level higher than the ISA devices in
|
|
// the code right above. But this doesn't work in
|
|
// the NoLegacy case because these devices haven't
|
|
// been added to the tree.
|
|
//
|
|
// Ideally, this code would just be moved above the ISA
|
|
// device detection code. That would be simpler. But
|
|
// That causes current ACPI machines to fail to dual-boot
|
|
// because their ARC paths would change.
|
|
//
|
|
|
|
// if (NoLegacy) {
|
|
//
|
|
// if (NextRelationship == Sibling) {
|
|
// PreviousEntry->Sibling = AcpiAdapterEntry;
|
|
// AcpiAdapterEntry->Parent = PreviousEntry->Parent;
|
|
// } else {
|
|
// PreviousEntry->Child = AdapterEntry;
|
|
// AdapterEntry->Parent = PreviousEntry;
|
|
// }
|
|
//
|
|
// PreviousEntry = AdapterEntry;
|
|
//
|
|
// } else {
|
|
|
|
if (NextRelationship == Sibling) {
|
|
PreviousEntry->Parent->Sibling = AcpiAdapterEntry;
|
|
AcpiAdapterEntry->Parent = PreviousEntry->Parent->Parent;
|
|
}
|
|
// }
|
|
|
|
NextRelationship = Sibling;
|
|
}
|
|
|
|
#if DBG
|
|
BlPrint("ACPI BIOS Data collection complete...\n");
|
|
#endif // DBG
|
|
|
|
#if DBG
|
|
BlPrint("Detection done. Press a key to display hardware info ...\n");
|
|
while ( ! HwGetKey ());
|
|
clrscrn ();
|
|
#endif
|
|
|
|
//
|
|
// Misc. supports. Note, the information collected here will NOT be
|
|
// written to hardware registry.
|
|
//
|
|
// 1. Collect video font information for vdm
|
|
//
|
|
|
|
GetVideoFontInformation();
|
|
|
|
//
|
|
// After all the components are detected, we collect EISA config data.
|
|
//
|
|
|
|
if (HwBusType == MACHINE_TYPE_EISA) {
|
|
|
|
Component = &AdapterEntry->ComponentEntry;
|
|
GetEisaConfigurationData(&AdapterEntry->ConfigurationData,
|
|
&Component->ConfigurationDataLength);
|
|
if (Component->ConfigurationDataLength) {
|
|
HwEisaConfigurationData = (FPUCHAR)AdapterEntry->ConfigurationData +
|
|
DATA_HEADER_SIZE;
|
|
HwEisaConfigurationSize = Component->ConfigurationDataLength -
|
|
DATA_HEADER_SIZE;
|
|
|
|
//
|
|
// Misc. detections based on Eisa config data
|
|
//
|
|
// Update Lpt and com controllers' irq information by examining
|
|
// the EISA configuration data.
|
|
//
|
|
|
|
GetIrqFromEisaData(FirstLpt, ParallelController);
|
|
GetIrqFromEisaData(FirstCom, SerialController);
|
|
}
|
|
}
|
|
|
|
|
|
#if DBG
|
|
CheckConfigurationTree(ConfigurationRoot);
|
|
#endif
|
|
|
|
//
|
|
// Update all the far pointers in the tree to flat 32 bit pointers
|
|
//
|
|
|
|
UpdateConfigurationTree(ConfigurationRoot);
|
|
|
|
//
|
|
// Set up returned values:
|
|
// Size of Heap space which should be preserved for configuration tree
|
|
// Pointer to the root of the configuration tree.
|
|
//
|
|
|
|
CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap(0, FALSE);
|
|
*BlHeapUsed = MAKE_FLAT_ADDRESS(CurrentEntry) -
|
|
MAKE_FLAT_ADDRESS(ConfigurationRoot);
|
|
*BlConfigurationTree = (ULONG)MAKE_FLAT_ADDRESS(ConfigurationRoot);
|
|
|
|
}
|
|
|
|
VOID
|
|
GetIrqFromEisaData(
|
|
FPFWCONFIGURATION_COMPONENT_DATA ControllerList,
|
|
CONFIGURATION_TYPE ControllerType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine updates all irq information for ControllerType components
|
|
in the controllerList by examinine the eisa configuration data.
|
|
|
|
Arguments:
|
|
|
|
ControllerList - Supplies a pointer to a component entry whoes irq will
|
|
be updated.
|
|
|
|
ControllerType - Supplies the controller type whoes irq will be searched
|
|
for.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry;
|
|
FPHWPARTIAL_RESOURCE_DESCRIPTOR Descriptor;
|
|
FPHWRESOURCE_DESCRIPTOR_LIST DescriptorList;
|
|
USHORT i, Port;
|
|
UCHAR Irq, Trigger;
|
|
|
|
CurrentEntry = ControllerList;
|
|
while (CurrentEntry &&
|
|
CurrentEntry->ComponentEntry.Type == ControllerType) {
|
|
if (CurrentEntry->ConfigurationData) {
|
|
DescriptorList = (FPHWRESOURCE_DESCRIPTOR_LIST)
|
|
CurrentEntry->ConfigurationData;
|
|
Port = 0;
|
|
for (i = 0; i < (USHORT)DescriptorList->Count; i++) {
|
|
Descriptor = &DescriptorList->PartialDescriptors[i];
|
|
if (Descriptor->Type == CmResourceTypePort) {
|
|
Port = (USHORT)Descriptor->u.Port.Start.LowPart;
|
|
break;
|
|
}
|
|
}
|
|
if (Port != 0) {
|
|
for (i = 0; i < (USHORT)DescriptorList->Count; i++) {
|
|
Descriptor = &DescriptorList->PartialDescriptors[i];
|
|
if (Descriptor->Type == CmResourceTypeInterrupt) {
|
|
if (HwEisaGetIrqFromPort(Port, &Irq, &Trigger)) {
|
|
if (Trigger == 0) { // EISA EDGE_TRIGGER
|
|
Descriptor->Flags = EDGE_TRIGGERED;
|
|
} else {
|
|
Descriptor->Flags = LEVEL_SENSITIVE;
|
|
}
|
|
Descriptor->u.Interrupt.Level = Irq;
|
|
Descriptor->u.Interrupt.Vector = Irq;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CurrentEntry = CurrentEntry->Sibling;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
UpdateComponentPointers(
|
|
FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine updates all the "far" pointer to 32 bit flat addresses
|
|
for a component entry.
|
|
|
|
Arguments:
|
|
|
|
CurrentEntry - Supplies a pointer to a component entry which will
|
|
be updated.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
FPULONG UpdatePointer;
|
|
FPVOID NextEntry;
|
|
ULONG FlatAddress;
|
|
|
|
//
|
|
// Update the child, parent, sibling and ConfigurationData
|
|
// far pointers to 32 bit flat addresses.
|
|
// N.B. After we update the pointers to flat addresses, they
|
|
// can no longer be accessed in real mode.
|
|
//
|
|
|
|
UpdatePointer = (FPULONG)&CurrentEntry->Child;
|
|
NextEntry = (FPVOID)CurrentEntry->Child;
|
|
FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
|
|
*UpdatePointer = FlatAddress;
|
|
|
|
UpdatePointer = (FPULONG)&CurrentEntry->Parent;
|
|
NextEntry = (FPVOID)CurrentEntry->Parent;
|
|
FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
|
|
*UpdatePointer = FlatAddress;
|
|
|
|
UpdatePointer = (FPULONG)&CurrentEntry->Sibling;
|
|
NextEntry = (FPVOID)CurrentEntry->Sibling;
|
|
FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
|
|
*UpdatePointer = FlatAddress;
|
|
|
|
UpdatePointer = (FPULONG)&CurrentEntry->ComponentEntry.Identifier;
|
|
NextEntry = (FPVOID)CurrentEntry->ComponentEntry.Identifier;
|
|
FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
|
|
*UpdatePointer = FlatAddress;
|
|
|
|
UpdatePointer = (FPULONG)&CurrentEntry->ConfigurationData;
|
|
NextEntry = (FPVOID)CurrentEntry->ConfigurationData;
|
|
FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
|
|
*UpdatePointer = FlatAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
UpdateConfigurationTree(
|
|
FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine traverses loader configuration tree and changes
|
|
all the "far" pointer to 32 bit flat addresses.
|
|
|
|
Arguments:
|
|
|
|
CurrentEntry - Supplies a pointer to a loader configuration
|
|
tree or subtree.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
FPFWCONFIGURATION_COMPONENT_DATA TempEntry;
|
|
|
|
while (CurrentEntry)
|
|
{
|
|
//
|
|
// Spin down finding the deepest child
|
|
//
|
|
while (CurrentEntry->Child) {
|
|
CurrentEntry = CurrentEntry->Child;
|
|
}
|
|
|
|
//
|
|
// Now we need to either move to the next sibling. If we
|
|
// don't have a sibling we need to walk up through the parents
|
|
// until we find an entry with a sibling. We have to save
|
|
// off the current entry since after we update the entry the
|
|
// pointer are no longer useable.
|
|
//
|
|
while (CurrentEntry) {
|
|
TempEntry = CurrentEntry;
|
|
|
|
if (CurrentEntry->Sibling != NULL) {
|
|
CurrentEntry = CurrentEntry->Sibling;
|
|
UpdateComponentPointers(TempEntry);
|
|
break;
|
|
} else {
|
|
CurrentEntry = CurrentEntry->Parent;
|
|
UpdateComponentPointers(TempEntry);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FPVOID
|
|
HwSetUpResourceDescriptor (
|
|
FPFWCONFIGURATION_COMPONENT Component,
|
|
PUCHAR Identifier,
|
|
PHWCONTROLLER_DATA ControlData,
|
|
USHORT SpecificDataLength,
|
|
PUCHAR SpecificData
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates space from far heap , puts the caller's controller
|
|
information to the space and sets up CONFIGURATION_COMPONENT
|
|
structure for the caller.
|
|
|
|
Arguments:
|
|
|
|
Component - Supplies the address the component whose configuration data
|
|
should be set up.
|
|
|
|
Identifier - Suppies a pointer to the identifier to identify the controller
|
|
|
|
ControlData - Supplies a point to a structure which describes
|
|
controller information.
|
|
|
|
SpecificDataLength - size of the device specific data. Device specific
|
|
data is the information not defined in the standard format.
|
|
|
|
SpecificData - Supplies a pointer to the device specific data.
|
|
|
|
|
|
Return Value:
|
|
|
|
Returns a far pointer to the Configuration data.
|
|
|
|
--*/
|
|
|
|
{
|
|
FPCHAR fpIdentifier;
|
|
FPHWRESOURCE_DESCRIPTOR_LIST fpDescriptor = NULL;
|
|
USHORT Length;
|
|
SHORT Count, i;
|
|
FPUCHAR fpSpecificData;
|
|
|
|
//
|
|
// Set up Identifier string for hardware component, if necessary.
|
|
//
|
|
|
|
if (Identifier) {
|
|
Length = strlen(Identifier) + 1;
|
|
Component->IdentifierLength = Length;
|
|
fpIdentifier = (FPUCHAR)HwAllocateHeap(Length, FALSE);
|
|
Component->Identifier = fpIdentifier;
|
|
_fstrcpy(fpIdentifier, Identifier);
|
|
} else {
|
|
Component->IdentifierLength = 0;
|
|
Component->Identifier = NULL;
|
|
}
|
|
|
|
//
|
|
// Set up configuration data for hardware component, if necessary
|
|
//
|
|
|
|
Count = ControlData->NumberPortEntries + ControlData->NumberIrqEntries +
|
|
ControlData->NumberMemoryEntries + ControlData->NumberDmaEntries;
|
|
|
|
if (SpecificDataLength) {
|
|
|
|
//
|
|
// if we have device specific data, we need to increment the count
|
|
// by one.
|
|
//
|
|
|
|
Count++;
|
|
}
|
|
|
|
if (Count >0) {
|
|
Length = (USHORT)(Count * sizeof(HWPARTIAL_RESOURCE_DESCRIPTOR) +
|
|
FIELD_OFFSET(HWRESOURCE_DESCRIPTOR_LIST, PartialDescriptors) +
|
|
SpecificDataLength);
|
|
fpDescriptor = (FPHWRESOURCE_DESCRIPTOR_LIST)HwAllocateHeap(Length, TRUE);
|
|
fpDescriptor->Count = Count;
|
|
|
|
//
|
|
// Copy all the partial descriptors to the destination descriptors
|
|
// except the last one. (The last partial descriptor may be a device
|
|
// specific data. It requires special handling.)
|
|
//
|
|
|
|
for (i = 0; i < (Count - 1); i++) {
|
|
fpDescriptor->PartialDescriptors[i] =
|
|
ControlData->DescriptorList[i];
|
|
}
|
|
|
|
//
|
|
// Set up the last partial descriptor. If it is a port, memory, irq or
|
|
// dma entry, we simply copy it. If the last one is for device specific
|
|
// data, we set up the length and copy the device spcific data to the end
|
|
// of the decriptor.
|
|
//
|
|
|
|
if (SpecificData) {
|
|
fpDescriptor->PartialDescriptors[Count - 1].Type =
|
|
RESOURCE_DEVICE_DATA;
|
|
fpDescriptor->PartialDescriptors[Count - 1].Flags = 0;
|
|
fpDescriptor->PartialDescriptors[Count - 1].u.DeviceSpecificData.DataSize =
|
|
SpecificDataLength;
|
|
fpSpecificData = (FPUCHAR)&(fpDescriptor->PartialDescriptors[Count]);
|
|
_fmemcpy(fpSpecificData, SpecificData, SpecificDataLength);
|
|
} else {
|
|
fpDescriptor->PartialDescriptors[Count - 1] =
|
|
ControlData->DescriptorList[Count - 1];
|
|
}
|
|
Component->ConfigurationDataLength = Length;
|
|
}
|
|
return(fpDescriptor);
|
|
}
|
|
VOID
|
|
HwSetUpFreeFormDataHeader (
|
|
FPHWRESOURCE_DESCRIPTOR_LIST Header,
|
|
USHORT Version,
|
|
USHORT Revision,
|
|
USHORT Flags,
|
|
ULONG DataSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initialize free formed data header. Note this routine
|
|
sets the the Header and initialize the FIRST PartialDescriptor only.
|
|
If the header contains more than one descriptor, the caller must handle
|
|
it itself.
|
|
|
|
Arguments:
|
|
|
|
Header - Supplies a pointer to the header to be initialized.
|
|
|
|
Version - Version number for the header.
|
|
|
|
Revision - Revision number for the header.
|
|
|
|
Flags - Free formed data flags. (Currently, it is undefined and
|
|
should be zero.)
|
|
|
|
DataSize - Size of the free formed data.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
Header->Version = Version;
|
|
Header->Revision = Revision;
|
|
Header->Count = 1;
|
|
Header->PartialDescriptors[0].Type = RESOURCE_DEVICE_DATA;
|
|
Header->PartialDescriptors[0].ShareDisposition = 0;
|
|
Header->PartialDescriptors[0].Flags = Flags;
|
|
Header->PartialDescriptors[0].u.DeviceSpecificData.DataSize = DataSize;
|
|
Header->PartialDescriptors[0].u.DeviceSpecificData.Reserved1 = 0;
|
|
Header->PartialDescriptors[0].u.DeviceSpecificData.Reserved2 = 0;
|
|
}
|
|
#if DBG
|
|
|
|
VOID
|
|
CheckComponentNode(
|
|
FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry
|
|
)
|
|
{
|
|
FPUCHAR NextEntry, DataPointer;
|
|
ULONG FlatAddress;
|
|
ULONG Length;
|
|
UCHAR IdString[40];
|
|
USHORT Count, i;
|
|
UCHAR Type;
|
|
FPHWRESOURCE_DESCRIPTOR_LIST DescriptorList;
|
|
FPHWPARTIAL_RESOURCE_DESCRIPTOR Descriptor;
|
|
|
|
FlatAddress = MAKE_FLAT_ADDRESS(CurrentEntry);
|
|
clrscrn ();
|
|
BlPrint("\n");
|
|
BlPrint("Current Node: %lx\n", FlatAddress);
|
|
BlPrint(" Type = %s\n", TypeName[CurrentEntry->ComponentEntry.Type]);
|
|
|
|
//
|
|
// Update the child, parent, sibling and ConfigurationData
|
|
// far pointers to 32 bit flat addresses.
|
|
// N.B. After we update the pointers to flat addresses, they
|
|
// can no longer be accessed in real mode.
|
|
//
|
|
|
|
NextEntry = (FPUCHAR)CurrentEntry->Child;
|
|
FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
|
|
if (FlatAddress > 0x60000 || (FlatAddress < 0x50000 && FlatAddress != 0)) {
|
|
BlPrint("Invalid address: Child = %lx\n", FlatAddress);
|
|
} else {
|
|
BlPrint("\tChild = %lx\n", FlatAddress);
|
|
}
|
|
|
|
NextEntry = (FPUCHAR)CurrentEntry->Parent;
|
|
FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
|
|
if (FlatAddress > 0x60000 || (FlatAddress < 0x50000 && FlatAddress != 0)) {
|
|
BlPrint("Invalid address: Parent = %lx\n", FlatAddress);
|
|
} else {
|
|
BlPrint("\tParent = %lx\n", FlatAddress);
|
|
}
|
|
|
|
NextEntry = (FPUCHAR)CurrentEntry->Sibling;
|
|
FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
|
|
if (FlatAddress > 0x60000 || (FlatAddress < 0x50000 && FlatAddress != 0)) {
|
|
BlPrint("Invalid address: Sibling = %lx\n", FlatAddress);
|
|
} else {
|
|
BlPrint("\tSibling = %lx\n", FlatAddress);
|
|
}
|
|
|
|
NextEntry = (FPUCHAR)CurrentEntry->ConfigurationData;
|
|
FlatAddress = MAKE_FLAT_ADDRESS(NextEntry);
|
|
if (FlatAddress > 0x60000 || (FlatAddress < 0x50000 && FlatAddress != 0)) {
|
|
BlPrint("Invalid address: ConfigurationData = %lx\n", FlatAddress);
|
|
} else {
|
|
BlPrint("\tConfigurationData = %lx\n", FlatAddress);
|
|
}
|
|
|
|
Length = CurrentEntry->ComponentEntry.IdentifierLength;
|
|
BlPrint("IdentifierLength = %lx\n", CurrentEntry->ComponentEntry.IdentifierLength);
|
|
if (Length > 0) {
|
|
_fstrcpy(IdString, CurrentEntry->ComponentEntry.Identifier);
|
|
BlPrint("Identifier = %s\n", IdString);
|
|
}
|
|
|
|
Length = CurrentEntry->ComponentEntry.ConfigurationDataLength;
|
|
BlPrint("ConfigdataLength = %lx\n", Length);
|
|
|
|
if (Length > 0) {
|
|
|
|
DescriptorList = (FPHWRESOURCE_DESCRIPTOR_LIST)CurrentEntry->ConfigurationData;
|
|
BlPrint("Version = %x, Revision = %x\n", DescriptorList->Version,
|
|
DescriptorList->Revision);
|
|
Count = (USHORT)DescriptorList->Count;
|
|
Descriptor = &DescriptorList->PartialDescriptors[0];
|
|
BlPrint("Count = %x\n", Count);
|
|
while (Count > 0) {
|
|
Type = Descriptor->Type;
|
|
if (Type == RESOURCE_PORT) {
|
|
BlPrint("Type = Port");
|
|
BlPrint("\tShareDisposition = %x\n", Descriptor->ShareDisposition);
|
|
BlPrint("PortFlags = %x\n", Descriptor->Flags);
|
|
BlPrint("PortStart = %x", Descriptor->u.Port.Start);
|
|
BlPrint("\tPortLength = %x\n", Descriptor->u.Port.Length);
|
|
} else if (Type == RESOURCE_DMA) {
|
|
BlPrint("Type = Dma");
|
|
BlPrint("\tShareDisposition = %x\n", Descriptor->ShareDisposition);
|
|
BlPrint("DmaFlags = %x\n", Descriptor->Flags);
|
|
BlPrint("DmaChannel = %x", Descriptor->u.Dma.Channel);
|
|
BlPrint("\tDmaPort = %lx\n", Descriptor->u.Dma.Port);
|
|
} else if (Type == RESOURCE_INTERRUPT) {
|
|
BlPrint("Type = Interrupt");
|
|
BlPrint("\tShareDisposition = %x\n", Descriptor->ShareDisposition);
|
|
BlPrint("InterruptFlags = %x\n", Descriptor->Flags);
|
|
BlPrint("Level = %x", Descriptor->u.Interrupt.Level);
|
|
BlPrint("\tVector = %x\n", Descriptor->u.Interrupt.Vector);
|
|
} else if (Type == RESOURCE_MEMORY) {
|
|
BlPrint("Type = Memory");
|
|
BlPrint("\tShareDisposition = %x\n", Descriptor->ShareDisposition);
|
|
BlPrint("MemoryFlags = %x\n", Descriptor->Flags);
|
|
BlPrint("Start1 = %lx", (ULONG)Descriptor->u.Memory.Start.LowPart);
|
|
BlPrint("\tStart2 = %lx", (ULONG)Descriptor->u.Memory.Start.HighPart);
|
|
BlPrint("\tLength = %lx\n", Descriptor->u.Memory.Length);
|
|
} else {
|
|
BlPrint("Type = Device Data\n");
|
|
Length = Descriptor->u.DeviceSpecificData.DataSize;
|
|
BlPrint("Size = %lx\n", Length);
|
|
DataPointer = (FPUCHAR)(Descriptor+1);
|
|
for (i = 0; (i < (USHORT)Length) && (i < 64); i++) {
|
|
BlPrint("%x ", *DataPointer);
|
|
DataPointer++;
|
|
}
|
|
break;
|
|
}
|
|
Count--;
|
|
Descriptor++;
|
|
}
|
|
}
|
|
while (HwGetKey() == 0) {
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CheckConfigurationTree(
|
|
FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry
|
|
)
|
|
{
|
|
FPFWCONFIGURATION_COMPONENT_DATA TempEntry;
|
|
|
|
while (CurrentEntry)
|
|
{
|
|
//
|
|
// Spin down finding the deepest child
|
|
//
|
|
while (CurrentEntry->Child) {
|
|
CurrentEntry = CurrentEntry->Child;
|
|
}
|
|
|
|
//
|
|
// Now we need to either move to the next sibling. If we
|
|
// don't have a sibling we need to walk up through the parents
|
|
// until we find an entry with a sibling. We have to save
|
|
// off the current entry since after we update the entry the
|
|
// pointer are no longer useable.
|
|
//
|
|
while (CurrentEntry) {
|
|
TempEntry = CurrentEntry;
|
|
|
|
if (CurrentEntry->Sibling != NULL) {
|
|
CurrentEntry = CurrentEntry->Sibling;
|
|
CheckComponentNode(TempEntry);
|
|
break;
|
|
} else {
|
|
CurrentEntry = CurrentEntry->Parent;
|
|
CheckComponentNode(TempEntry);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|