mirror of
https://github.com/reactos/reactos.git
synced 2024-08-22 03:12:51 +00:00
1670 lines
51 KiB
C
1670 lines
51 KiB
C
/*
|
|
* PROJECT: ReactOS HAL
|
|
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
|
* FILE: hal/halx86/legacy/bussupp.c
|
|
* PURPOSE: HAL Legacy Bus Support Code
|
|
* PROGRAMMERS: ReactOS Portable Systems Group
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include <hal.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
CODE_SEG("INIT")
|
|
PBUS_HANDLER
|
|
NTAPI
|
|
HalpAllocateAndInitPciBusHandler(
|
|
IN ULONG PciType,
|
|
IN ULONG BusNo,
|
|
IN BOOLEAN TestAllocation
|
|
);
|
|
|
|
CODE_SEG("INIT")
|
|
VOID
|
|
NTAPI
|
|
HalpFixupPciSupportedRanges(
|
|
IN ULONG BusCount
|
|
);
|
|
|
|
CODE_SEG("INIT")
|
|
NTSTATUS
|
|
NTAPI
|
|
HalpGetChipHacks(
|
|
IN USHORT VendorId,
|
|
IN USHORT DeviceId,
|
|
IN UCHAR RevisionId,
|
|
IN PULONG HackFlags
|
|
);
|
|
|
|
CODE_SEG("INIT")
|
|
BOOLEAN
|
|
NTAPI
|
|
HalpGetPciBridgeConfig(
|
|
IN ULONG PciType,
|
|
IN PUCHAR BusCount
|
|
);
|
|
|
|
CODE_SEG("INIT")
|
|
BOOLEAN
|
|
NTAPI
|
|
HalpIsBridgeDevice(
|
|
IN PPCI_COMMON_CONFIG PciData
|
|
);
|
|
|
|
CODE_SEG("INIT")
|
|
BOOLEAN
|
|
NTAPI
|
|
HalpIsIdeDevice(
|
|
IN PPCI_COMMON_CONFIG PciData
|
|
);
|
|
|
|
CODE_SEG("INIT")
|
|
BOOLEAN
|
|
NTAPI
|
|
HalpIsRecognizedCard(
|
|
IN PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo,
|
|
IN PPCI_COMMON_CONFIG PciData,
|
|
IN ULONG Flags
|
|
);
|
|
|
|
CODE_SEG("INIT")
|
|
BOOLEAN
|
|
NTAPI
|
|
HalpIsValidPCIDevice(
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PCI_SLOT_NUMBER Slot
|
|
);
|
|
|
|
CODE_SEG("INIT")
|
|
NTSTATUS
|
|
NTAPI
|
|
HalpMarkChipsetDecode(
|
|
IN BOOLEAN OverrideEnable
|
|
);
|
|
|
|
CODE_SEG("INIT")
|
|
VOID
|
|
NTAPI
|
|
HalpRegisterInternalBusHandlers(
|
|
VOID
|
|
);
|
|
|
|
CODE_SEG("INIT")
|
|
VOID
|
|
NTAPI
|
|
ShowSize(
|
|
IN ULONG Size
|
|
);
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
extern KSPIN_LOCK HalpPCIConfigLock;
|
|
ULONG HalpPciIrqMask;
|
|
|
|
/* PRIVATE FUNCTIONS **********************************************************/
|
|
|
|
PBUS_HANDLER
|
|
NTAPI
|
|
HalpAllocateBusHandler(IN INTERFACE_TYPE InterfaceType,
|
|
IN BUS_DATA_TYPE BusDataType,
|
|
IN ULONG BusNumber,
|
|
IN INTERFACE_TYPE ParentBusInterfaceType,
|
|
IN ULONG ParentBusNumber,
|
|
IN ULONG BusSpecificData)
|
|
{
|
|
PBUS_HANDLER Bus;
|
|
|
|
/* Register the bus handler */
|
|
HalRegisterBusHandler(InterfaceType,
|
|
BusDataType,
|
|
BusNumber,
|
|
ParentBusInterfaceType,
|
|
ParentBusNumber,
|
|
BusSpecificData,
|
|
NULL,
|
|
&Bus);
|
|
if (!Bus)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* Check for a valid interface */
|
|
if (InterfaceType != InterfaceTypeUndefined)
|
|
{
|
|
/* Allocate address ranges and zero them out */
|
|
Bus->BusAddresses = ExAllocatePoolWithTag(NonPagedPoolMustSucceed,
|
|
sizeof(SUPPORTED_RANGES),
|
|
TAG_HAL);
|
|
RtlZeroMemory(Bus->BusAddresses, sizeof(SUPPORTED_RANGES));
|
|
|
|
/* Build the data structure */
|
|
Bus->BusAddresses->Version = HAL_SUPPORTED_RANGE_VERSION;
|
|
Bus->BusAddresses->Dma.Limit = 7;
|
|
Bus->BusAddresses->Memory.Limit = 0xFFFFFFFF;
|
|
Bus->BusAddresses->IO.Limit = 0xFFFF;
|
|
Bus->BusAddresses->IO.SystemAddressSpace = 1;
|
|
Bus->BusAddresses->PrefetchMemory.Base = 1;
|
|
}
|
|
|
|
/* Return the bus address */
|
|
return Bus;
|
|
}
|
|
|
|
#ifndef _MINIHAL_
|
|
CODE_SEG("INIT")
|
|
VOID
|
|
NTAPI
|
|
HalpRegisterInternalBusHandlers(VOID)
|
|
{
|
|
PBUS_HANDLER Bus;
|
|
|
|
/* Only do processor 1 */
|
|
if (KeGetCurrentPrcb()->Number) return;
|
|
|
|
/* Register root support */
|
|
HalpInitBusHandler();
|
|
|
|
/* Allocate the system bus */
|
|
Bus = HalpAllocateBusHandler(Internal,
|
|
ConfigurationSpaceUndefined,
|
|
0,
|
|
InterfaceTypeUndefined,
|
|
0,
|
|
0);
|
|
if (Bus)
|
|
{
|
|
/* Set it up */
|
|
Bus->GetInterruptVector = HalpGetSystemInterruptVector;
|
|
Bus->TranslateBusAddress = HalpTranslateSystemBusAddress;
|
|
}
|
|
|
|
/* Allocate the CMOS bus */
|
|
Bus = HalpAllocateBusHandler(InterfaceTypeUndefined,
|
|
Cmos,
|
|
0,
|
|
InterfaceTypeUndefined,
|
|
0,
|
|
0);
|
|
if (Bus)
|
|
{
|
|
/* Set it up */
|
|
Bus->GetBusData = HalpcGetCmosData;
|
|
Bus->SetBusData = HalpcSetCmosData;
|
|
}
|
|
|
|
/* Allocate the CMOS bus */
|
|
Bus = HalpAllocateBusHandler(InterfaceTypeUndefined,
|
|
Cmos,
|
|
1,
|
|
InterfaceTypeUndefined,
|
|
0,
|
|
0);
|
|
if (Bus)
|
|
{
|
|
/* Set it up */
|
|
Bus->GetBusData = HalpcGetCmosData;
|
|
Bus->SetBusData = HalpcSetCmosData;
|
|
}
|
|
|
|
/* Allocate ISA bus */
|
|
Bus = HalpAllocateBusHandler(Isa,
|
|
ConfigurationSpaceUndefined,
|
|
0,
|
|
Internal,
|
|
0,
|
|
0);
|
|
if (Bus)
|
|
{
|
|
/* Set it up */
|
|
Bus->GetBusData = HalpNoBusData;
|
|
Bus->BusAddresses->Memory.Limit = 0xFFFFFF;
|
|
Bus->TranslateBusAddress = HalpTranslateIsaBusAddress;
|
|
}
|
|
|
|
/* No support for EISA or MCA */
|
|
ASSERT(HalpBusType == MACHINE_TYPE_ISA);
|
|
}
|
|
#endif // _MINIHAL_
|
|
|
|
#ifndef _MINIHAL_
|
|
CODE_SEG("INIT")
|
|
NTSTATUS
|
|
NTAPI
|
|
HalpMarkChipsetDecode(BOOLEAN OverrideEnable)
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING KeyString;
|
|
ULONG Data = OverrideEnable;
|
|
HANDLE KeyHandle, Handle;
|
|
|
|
/* Open CCS key */
|
|
RtlInitUnicodeString(&KeyString,
|
|
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET");
|
|
Status = HalpOpenRegistryKey(&Handle, 0, &KeyString, KEY_ALL_ACCESS, FALSE);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Open PNP Bios key */
|
|
RtlInitUnicodeString(&KeyString, L"Control\\Biosinfo\\PNPBios");
|
|
Status = HalpOpenRegistryKey(&KeyHandle,
|
|
Handle,
|
|
&KeyString,
|
|
KEY_ALL_ACCESS,
|
|
TRUE);
|
|
|
|
/* Close root key */
|
|
ZwClose(Handle);
|
|
|
|
/* Check if PNP BIOS key exists */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Set the override value */
|
|
RtlInitUnicodeString(&KeyString, L"FullDecodeChipsetOverride");
|
|
Status = ZwSetValueKey(KeyHandle,
|
|
&KeyString,
|
|
0,
|
|
REG_DWORD,
|
|
&Data,
|
|
sizeof(Data));
|
|
|
|
/* Close subkey */
|
|
ZwClose(KeyHandle);
|
|
}
|
|
}
|
|
|
|
/* Return status */
|
|
return Status;
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
PBUS_HANDLER
|
|
NTAPI
|
|
HalpAllocateAndInitPciBusHandler(IN ULONG PciType,
|
|
IN ULONG BusNo,
|
|
IN BOOLEAN TestAllocation)
|
|
{
|
|
PBUS_HANDLER Bus;
|
|
PPCIPBUSDATA BusData;
|
|
|
|
/* Allocate the bus handler */
|
|
Bus = HalpAllocateBusHandler(PCIBus,
|
|
PCIConfiguration,
|
|
BusNo,
|
|
Internal,
|
|
0,
|
|
sizeof(PCIPBUSDATA));
|
|
|
|
/* Set it up */
|
|
Bus->GetBusData = HalpGetPCIData;
|
|
Bus->SetBusData = HalpSetPCIData;
|
|
Bus->GetInterruptVector = HalpGetPCIIntOnISABus;
|
|
Bus->AdjustResourceList = HalpAdjustPCIResourceList;
|
|
Bus->AssignSlotResources = HalpAssignPCISlotResources;
|
|
Bus->BusAddresses->Dma.Limit = 0;
|
|
|
|
/* Get our custom bus data */
|
|
BusData = (PPCIPBUSDATA)Bus->BusData;
|
|
|
|
/* Setup custom bus data */
|
|
BusData->CommonData.Tag = PCI_DATA_TAG;
|
|
BusData->CommonData.Version = PCI_DATA_VERSION;
|
|
BusData->CommonData.ReadConfig = HalpReadPCIConfig;
|
|
BusData->CommonData.WriteConfig = HalpWritePCIConfig;
|
|
BusData->CommonData.Pin2Line = HalpPCIPin2ISALine;
|
|
BusData->CommonData.Line2Pin = HalpPCIISALine2Pin;
|
|
BusData->MaxDevice = PCI_MAX_DEVICES;
|
|
BusData->GetIrqRange = HalpGetISAFixedPCIIrq;
|
|
|
|
/* Initialize the bitmap */
|
|
RtlInitializeBitMap(&BusData->DeviceConfigured, BusData->ConfiguredBits, 256);
|
|
|
|
/* Check the type of PCI bus */
|
|
switch (PciType)
|
|
{
|
|
/* Type 1 PCI Bus */
|
|
case 1:
|
|
|
|
/* Copy the Type 1 handler data */
|
|
RtlCopyMemory(&PCIConfigHandler,
|
|
&PCIConfigHandlerType1,
|
|
sizeof(PCIConfigHandler));
|
|
|
|
/* Set correct I/O Ports */
|
|
BusData->Config.Type1.Address = PCI_TYPE1_ADDRESS_PORT;
|
|
BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT;
|
|
break;
|
|
|
|
/* Type 2 PCI Bus */
|
|
case 2:
|
|
|
|
/* Copy the Type 1 handler data */
|
|
RtlCopyMemory(&PCIConfigHandler,
|
|
&PCIConfigHandlerType2,
|
|
sizeof (PCIConfigHandler));
|
|
|
|
/* Set correct I/O Ports */
|
|
BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT;
|
|
BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT;
|
|
BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE;
|
|
|
|
/* Only 16 devices supported, not 32 */
|
|
BusData->MaxDevice = 16;
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Invalid type */
|
|
DbgPrint("HAL: Unnkown PCI type\n");
|
|
}
|
|
|
|
/* Return the bus handler */
|
|
return Bus;
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
BOOLEAN
|
|
NTAPI
|
|
HalpIsValidPCIDevice(IN PBUS_HANDLER BusHandler,
|
|
IN PCI_SLOT_NUMBER Slot)
|
|
{
|
|
UCHAR DataBuffer[PCI_COMMON_HDR_LENGTH];
|
|
PPCI_COMMON_CONFIG PciHeader = (PVOID)DataBuffer;
|
|
ULONG i;
|
|
ULONG_PTR Address;
|
|
|
|
/* Read the PCI header */
|
|
HalpReadPCIConfig(BusHandler, Slot, PciHeader, 0, PCI_COMMON_HDR_LENGTH);
|
|
|
|
/* Make sure it's a valid device */
|
|
if ((PciHeader->VendorID == PCI_INVALID_VENDORID) ||
|
|
(PCI_CONFIGURATION_TYPE(PciHeader) != PCI_DEVICE_TYPE))
|
|
{
|
|
/* Bail out */
|
|
return FALSE;
|
|
}
|
|
|
|
/* Make sure interrupt numbers make sense */
|
|
if (((PciHeader->u.type0.InterruptPin) &&
|
|
(PciHeader->u.type0.InterruptPin > 4)) ||
|
|
(PciHeader->u.type0.InterruptLine & 0x70))
|
|
{
|
|
/* Bail out */
|
|
return FALSE;
|
|
}
|
|
|
|
/* Now scan PCI BARs */
|
|
for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
|
|
{
|
|
/* Check what kind of address it is */
|
|
Address = PciHeader->u.type0.BaseAddresses[i];
|
|
if (Address & PCI_ADDRESS_IO_SPACE)
|
|
{
|
|
/* Highest I/O port is 65535 */
|
|
if (Address > 0xFFFF) return FALSE;
|
|
}
|
|
else
|
|
{
|
|
/* MMIO should be higher than 0x80000 */
|
|
if ((Address > 0xF) && (Address < 0x80000)) return FALSE;
|
|
}
|
|
|
|
/* Is this a 64-bit address? */
|
|
if (!(Address & PCI_ADDRESS_IO_SPACE) &&
|
|
((Address & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT))
|
|
{
|
|
/* Check the next-next entry, since this one 64-bits wide */
|
|
i++;
|
|
}
|
|
}
|
|
|
|
/* Header, interrupt and address data all make sense */
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOLEAN WarningsGiven[5];
|
|
|
|
CODE_SEG("INIT")
|
|
NTSTATUS
|
|
NTAPI
|
|
HalpGetChipHacks(IN USHORT VendorId,
|
|
IN USHORT DeviceId,
|
|
IN UCHAR RevisionId,
|
|
IN PULONG HackFlags)
|
|
{
|
|
UNICODE_STRING KeyName, ValueName;
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE KeyHandle;
|
|
WCHAR Buffer[32];
|
|
KEY_VALUE_PARTIAL_INFORMATION PartialInfo;
|
|
ULONG ResultLength;
|
|
|
|
/* Setup the object attributes for the key */
|
|
RtlInitUnicodeString(&KeyName,
|
|
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\"
|
|
L"Control\\HAL");
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
/* Open the key */
|
|
Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
/* Query value */
|
|
swprintf(Buffer, L"%04X%04X", VendorId, DeviceId);
|
|
RtlInitUnicodeString(&ValueName, Buffer);
|
|
Status = ZwQueryValueKey(KeyHandle,
|
|
&ValueName,
|
|
KeyValuePartialInformation,
|
|
&PartialInfo,
|
|
sizeof(PartialInfo),
|
|
&ResultLength);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Return the flags */
|
|
DbgPrint("\tFound HackFlags for your chipset\n");
|
|
*HackFlags = *(PULONG)PartialInfo.Data;
|
|
DbgPrint("\t\tHack Flags: %lx (Hack Revision: %lx-Your Revision: %lx)\n",
|
|
*HackFlags, HALP_REVISION_FROM_HACK_FLAGS(*HackFlags), RevisionId);
|
|
|
|
/* Does it apply to this revision? */
|
|
if ((RevisionId) && (RevisionId >= (HALP_REVISION_FROM_HACK_FLAGS(*HackFlags))))
|
|
{
|
|
/* Read the revision flags */
|
|
*HackFlags = HALP_REVISION_HACK_FLAGS(*HackFlags);
|
|
}
|
|
|
|
/* Throw out revision data */
|
|
*HackFlags = HALP_HACK_FLAGS(*HackFlags);
|
|
if (!*HackFlags) DbgPrint("\tNo HackFlags for your chipset's revision!\n");
|
|
}
|
|
|
|
/* Close the handle and return */
|
|
ZwClose(KeyHandle);
|
|
return Status;
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
BOOLEAN
|
|
NTAPI
|
|
HalpIsRecognizedCard(IN PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo,
|
|
IN PPCI_COMMON_CONFIG PciData,
|
|
IN ULONG Flags)
|
|
{
|
|
ULONG ElementCount, i;
|
|
PPCI_CARD_DESCRIPTOR CardDescriptor;
|
|
|
|
/* How many PCI Cards that we know about? */
|
|
ElementCount = PciRegistryInfo->ElementCount;
|
|
if (!ElementCount) return FALSE;
|
|
|
|
/* Loop all descriptors */
|
|
CardDescriptor = &PciRegistryInfo->CardList[0];
|
|
for (i = 0; i < ElementCount; i++, CardDescriptor++)
|
|
{
|
|
/* Check for flag match */
|
|
if (CardDescriptor->Flags != Flags) continue;
|
|
|
|
/* Check for VID-PID match */
|
|
if ((CardDescriptor->VendorID != PciData->VendorID) ||
|
|
(CardDescriptor->DeviceID != PciData->DeviceID))
|
|
{
|
|
/* Skip */
|
|
continue;
|
|
}
|
|
|
|
/* Check for revision match, if requested */
|
|
if ((CardDescriptor->Flags & HALP_CHECK_CARD_REVISION_ID) &&
|
|
(CardDescriptor->RevisionID != PciData->RevisionID))
|
|
{
|
|
/* Skip */
|
|
continue;
|
|
}
|
|
|
|
/* Check what kind of device this is */
|
|
switch (PCI_CONFIGURATION_TYPE(PciData))
|
|
{
|
|
/* CardBUS Bridge */
|
|
case PCI_CARDBUS_BRIDGE_TYPE:
|
|
|
|
/* This means the real device header is in the device-specific data */
|
|
PciData = (PPCI_COMMON_CONFIG)PciData->DeviceSpecific;
|
|
|
|
/* Normal PCI device */
|
|
case PCI_DEVICE_TYPE:
|
|
|
|
/* Check for subvendor match, if requested */
|
|
if ((CardDescriptor->Flags & HALP_CHECK_CARD_SUBVENDOR_ID) &&
|
|
(CardDescriptor->SubsystemVendorID != PciData->u.type0.SubVendorID))
|
|
{
|
|
/* Skip */
|
|
continue;
|
|
}
|
|
|
|
/* Check for subsystem match, if requested */
|
|
if ((CardDescriptor->Flags & HALP_CHECK_CARD_SUBSYSTEM_ID) &&
|
|
(CardDescriptor->SubsystemID != PciData->u.type0.SubSystemID))
|
|
{
|
|
/* Skip */
|
|
continue;
|
|
}
|
|
|
|
/* You made it! */
|
|
return TRUE;
|
|
|
|
/* PCI Bridge -- don't bother */
|
|
case PCI_BRIDGE_TYPE:
|
|
default:
|
|
|
|
/* Recognize it */
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/* This means the card isn't recognized */
|
|
return FALSE;
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
BOOLEAN
|
|
NTAPI
|
|
HalpIsIdeDevice(IN PPCI_COMMON_CONFIG PciData)
|
|
{
|
|
/* Simple test first */
|
|
if ((PciData->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
|
|
(PciData->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
|
|
{
|
|
/* The device is nice enough to admit it */
|
|
return TRUE;
|
|
}
|
|
|
|
/* Symphony 82C101 */
|
|
if (PciData->VendorID == 0x1C1C) return TRUE;
|
|
|
|
/* ALi MS4803 or M5219 */
|
|
if ((PciData->VendorID == 0x10B9) &&
|
|
((PciData->DeviceID == 0x5215) || (PciData->DeviceID == 0x5219)))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
/* Appian Technology */
|
|
if ((PciData->VendorID == 0x1097) && (PciData->DeviceID == 0x38)) return TRUE;
|
|
|
|
/* Compaq Triflex Dual EIDE Controller */
|
|
if ((PciData->VendorID == 0xE11) && (PciData->DeviceID == 0xAE33)) return TRUE;
|
|
|
|
/* Micron PC Tech RZ1000 */
|
|
if ((PciData->VendorID == 0x1042) && (PciData->DeviceID == 0x1000)) return TRUE;
|
|
|
|
/* SiS 85C601 or 5513 [IDE] */
|
|
if ((PciData->VendorID == 0x1039) &&
|
|
((PciData->DeviceID == 0x601) || (PciData->DeviceID == 0x5513)))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
/* Symphony Labs W83769F */
|
|
if ((PciData->VendorID == 0x10AD) &&
|
|
((PciData->DeviceID == 0x1) || (PciData->DeviceID == 0x150)))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
/* UMC UM8673F */
|
|
if ((PciData->VendorID == 0x1060) && (PciData->DeviceID == 0x101)) return TRUE;
|
|
|
|
/* You've survived */
|
|
return FALSE;
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
BOOLEAN
|
|
NTAPI
|
|
HalpIsBridgeDevice(IN PPCI_COMMON_CONFIG PciData)
|
|
{
|
|
/* Either this is a PCI-to-PCI Bridge, or a CardBUS Bridge */
|
|
return (((PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE) &&
|
|
(PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
|
|
(PciData->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI)) ||
|
|
((PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE) &&
|
|
(PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
|
|
(PciData->SubClass == PCI_SUBCLASS_BR_CARDBUS)));
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
BOOLEAN
|
|
NTAPI
|
|
HalpGetPciBridgeConfig(IN ULONG PciType,
|
|
IN PUCHAR BusCount)
|
|
{
|
|
PCI_SLOT_NUMBER PciSlot;
|
|
ULONG i, j, k;
|
|
UCHAR DataBuffer[PCI_COMMON_HDR_LENGTH];
|
|
PPCI_COMMON_CONFIG PciData = (PPCI_COMMON_CONFIG)DataBuffer;
|
|
PBUS_HANDLER BusHandler;
|
|
|
|
/* Loop PCI buses */
|
|
PciSlot.u.bits.Reserved = 0;
|
|
for (i = 0; i < *BusCount; i++)
|
|
{
|
|
/* Get the bus handler */
|
|
BusHandler = HalHandlerForBus(PCIBus, i);
|
|
|
|
/* Loop every device */
|
|
for (j = 0; j < PCI_MAX_DEVICES; j++)
|
|
{
|
|
/* Loop every function */
|
|
PciSlot.u.bits.DeviceNumber = j;
|
|
for (k = 0; k < PCI_MAX_FUNCTION; k++)
|
|
{
|
|
/* Build the final slot structure */
|
|
PciSlot.u.bits.FunctionNumber = k;
|
|
|
|
/* Read the configuration information */
|
|
HalpReadPCIConfig(BusHandler,
|
|
PciSlot,
|
|
PciData,
|
|
0,
|
|
PCI_COMMON_HDR_LENGTH);
|
|
|
|
/* Skip if this is an invalid function */
|
|
if (PciData->VendorID == PCI_INVALID_VENDORID) continue;
|
|
|
|
/* Make sure that this is a PCI bridge or a cardbus bridge */
|
|
if (!HalpIsBridgeDevice(PciData)) continue;
|
|
|
|
/* Not supported */
|
|
if (!WarningsGiven[2]++) DPRINT1("Your machine has a PCI-to-PCI or CardBUS Bridge. PCI devices may fail!\n");
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If we exited the loop, then there's no bridge to worry about */
|
|
return FALSE;
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
VOID
|
|
NTAPI
|
|
HalpFixupPciSupportedRanges(IN ULONG BusCount)
|
|
{
|
|
ULONG i;
|
|
PBUS_HANDLER Bus, ParentBus;
|
|
|
|
/* Loop all buses */
|
|
for (i = 0; i < BusCount; i++)
|
|
{
|
|
/* Get PCI bus handler */
|
|
Bus = HalHandlerForBus(PCIBus, i);
|
|
|
|
/* Loop all parent buses */
|
|
ParentBus = Bus->ParentHandler;
|
|
while (ParentBus)
|
|
{
|
|
/* Should merge addresses */
|
|
if (!WarningsGiven[0]++) DPRINT1("Found parent bus (indicating PCI Bridge). PCI devices may fail!\n");
|
|
|
|
/* Check the next parent */
|
|
ParentBus = ParentBus->ParentHandler;
|
|
}
|
|
}
|
|
|
|
/* Loop all buses again */
|
|
for (i = 0; i < BusCount; i++)
|
|
{
|
|
/* Get PCI bus handler */
|
|
Bus = HalHandlerForBus(PCIBus, i);
|
|
|
|
/* Check if this is a PCI 2.2 Bus with Subtractive Decode */
|
|
if (!((PPCIPBUSDATA)Bus->BusData)->Subtractive)
|
|
{
|
|
/* Loop all parent buses */
|
|
ParentBus = Bus->ParentHandler;
|
|
while (ParentBus)
|
|
{
|
|
/* But check only PCI parent buses specifically */
|
|
if (ParentBus->InterfaceType == PCIBus)
|
|
{
|
|
/* Should trim addresses */
|
|
if (!WarningsGiven[1]++) DPRINT1("Found parent PCI Bus (indicating PCI-to-PCI Bridge). PCI devices may fail!\n");
|
|
}
|
|
|
|
/* Check the next parent */
|
|
ParentBus = ParentBus->ParentHandler;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Loop buses one last time */
|
|
for (i = 0; i < BusCount; i++)
|
|
{
|
|
/* Get the PCI bus handler */
|
|
Bus = HalHandlerForBus(PCIBus, i);
|
|
|
|
/* Sort and combine (trim) bus address range information */
|
|
DPRINT("Warning: Bus addresses not being optimized!\n");
|
|
}
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
VOID
|
|
NTAPI
|
|
ShowSize(ULONG x)
|
|
{
|
|
if (!x) return;
|
|
DbgPrint(" [size=");
|
|
if (x < 1024)
|
|
{
|
|
DbgPrint("%d", (int) x);
|
|
}
|
|
else if (x < 1048576)
|
|
{
|
|
DbgPrint("%dK", (int)(x / 1024));
|
|
}
|
|
else if (x < 0x80000000)
|
|
{
|
|
DbgPrint("%dM", (int)(x / 1048576));
|
|
}
|
|
else
|
|
{
|
|
DbgPrint("%d", x);
|
|
}
|
|
DbgPrint("]");
|
|
}
|
|
|
|
/*
|
|
* These includes are required to define
|
|
* the ClassTable and VendorTable arrays.
|
|
*/
|
|
#include "pci_classes.h"
|
|
#include "pci_vendors.h"
|
|
CODE_SEG("INIT")
|
|
VOID
|
|
NTAPI
|
|
HalpDebugPciDumpBus(IN ULONG i,
|
|
IN ULONG j,
|
|
IN ULONG k,
|
|
IN PPCI_COMMON_CONFIG PciData)
|
|
{
|
|
PCHAR p, ClassName, Boundary, SubClassName, VendorName, ProductName, SubVendorName;
|
|
UCHAR HeaderType;
|
|
ULONG Length;
|
|
CHAR LookupString[16] = "";
|
|
CHAR bSubClassName[64] = "Unknown";
|
|
CHAR bVendorName[64] = "";
|
|
CHAR bProductName[128] = "Unknown device";
|
|
CHAR bSubVendorName[128] = "Unknown";
|
|
ULONG Size, Mem, b;
|
|
|
|
HeaderType = (PciData->HeaderType & ~PCI_MULTIFUNCTION);
|
|
|
|
/* Isolate the class name */
|
|
sprintf(LookupString, "C %02x ", PciData->BaseClass);
|
|
ClassName = strstr((PCHAR)ClassTable, LookupString);
|
|
if (ClassName)
|
|
{
|
|
/* Isolate the subclass name */
|
|
ClassName += strlen("C 00 ");
|
|
Boundary = strstr(ClassName, "\nC ");
|
|
sprintf(LookupString, "\n\t%02x ", PciData->SubClass);
|
|
SubClassName = strstr(ClassName, LookupString);
|
|
if (Boundary && SubClassName > Boundary)
|
|
{
|
|
SubClassName = NULL;
|
|
}
|
|
if (!SubClassName)
|
|
{
|
|
SubClassName = ClassName;
|
|
}
|
|
else
|
|
{
|
|
SubClassName += strlen("\n\t00 ");
|
|
}
|
|
/* Copy the subclass into our buffer */
|
|
p = strpbrk(SubClassName, "\r\n");
|
|
Length = p - SubClassName;
|
|
if (Length >= sizeof(bSubClassName)) Length = sizeof(bSubClassName) - 1;
|
|
strncpy(bSubClassName, SubClassName, Length);
|
|
bSubClassName[Length] = '\0';
|
|
}
|
|
|
|
/* Isolate the vendor name */
|
|
sprintf(LookupString, "\r\n%04x ", PciData->VendorID);
|
|
VendorName = strstr((PCHAR)VendorTable, LookupString);
|
|
if (VendorName)
|
|
{
|
|
/* Copy the vendor name into our buffer */
|
|
VendorName += strlen("\r\n0000 ");
|
|
p = strpbrk(VendorName, "\r\n");
|
|
Length = p - VendorName;
|
|
if (Length >= sizeof(bVendorName)) Length = sizeof(bVendorName) - 1;
|
|
strncpy(bVendorName, VendorName, Length);
|
|
bVendorName[Length] = '\0';
|
|
p += strlen("\r\n");
|
|
while (*p == '\t' || *p == '#')
|
|
{
|
|
p = strpbrk(p, "\r\n");
|
|
p += strlen("\r\n");
|
|
}
|
|
Boundary = p;
|
|
|
|
/* Isolate the product name */
|
|
sprintf(LookupString, "\t%04x ", PciData->DeviceID);
|
|
ProductName = strstr(VendorName, LookupString);
|
|
if (Boundary && ProductName >= Boundary)
|
|
{
|
|
ProductName = NULL;
|
|
}
|
|
if (ProductName)
|
|
{
|
|
/* Copy the product name into our buffer */
|
|
ProductName += strlen("\t0000 ");
|
|
p = strpbrk(ProductName, "\r\n");
|
|
Length = p - ProductName;
|
|
if (Length >= sizeof(bProductName)) Length = sizeof(bProductName) - 1;
|
|
strncpy(bProductName, ProductName, Length);
|
|
bProductName[Length] = '\0';
|
|
p += strlen("\r\n");
|
|
while ((*p == '\t' && *(p + 1) == '\t') || *p == '#')
|
|
{
|
|
p = strpbrk(p, "\r\n");
|
|
p += strlen("\r\n");
|
|
}
|
|
Boundary = p;
|
|
SubVendorName = NULL;
|
|
|
|
if (HeaderType == PCI_DEVICE_TYPE)
|
|
{
|
|
/* Isolate the subvendor and subsystem name */
|
|
sprintf(LookupString,
|
|
"\t\t%04x %04x ",
|
|
PciData->u.type0.SubVendorID,
|
|
PciData->u.type0.SubSystemID);
|
|
SubVendorName = strstr(ProductName, LookupString);
|
|
if (Boundary && SubVendorName >= Boundary)
|
|
{
|
|
SubVendorName = NULL;
|
|
}
|
|
}
|
|
if (SubVendorName)
|
|
{
|
|
/* Copy the subvendor name into our buffer */
|
|
SubVendorName += strlen("\t\t0000 0000 ");
|
|
p = strpbrk(SubVendorName, "\r\n");
|
|
Length = p - SubVendorName;
|
|
if (Length >= sizeof(bSubVendorName)) Length = sizeof(bSubVendorName) - 1;
|
|
strncpy(bSubVendorName, SubVendorName, Length);
|
|
bSubVendorName[Length] = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Print out the data */
|
|
DbgPrint("%02x:%02x.%x %s [%02x%02x]: %s %s [%04x:%04x] (rev %02x)\n",
|
|
i,
|
|
j,
|
|
k,
|
|
bSubClassName,
|
|
PciData->BaseClass,
|
|
PciData->SubClass,
|
|
bVendorName,
|
|
bProductName,
|
|
PciData->VendorID,
|
|
PciData->DeviceID,
|
|
PciData->RevisionID);
|
|
|
|
if (HeaderType == PCI_DEVICE_TYPE)
|
|
{
|
|
DbgPrint("\tSubsystem: %s [%04x:%04x]\n",
|
|
bSubVendorName,
|
|
PciData->u.type0.SubVendorID,
|
|
PciData->u.type0.SubSystemID);
|
|
}
|
|
|
|
/* Print out and decode flags */
|
|
DbgPrint("\tFlags:");
|
|
if (PciData->Command & PCI_ENABLE_BUS_MASTER) DbgPrint(" bus master,");
|
|
if (PciData->Status & PCI_STATUS_66MHZ_CAPABLE) DbgPrint(" 66MHz,");
|
|
if ((PciData->Status & PCI_STATUS_DEVSEL) == 0x000) DbgPrint(" fast devsel,");
|
|
if ((PciData->Status & PCI_STATUS_DEVSEL) == 0x200) DbgPrint(" medium devsel,");
|
|
if ((PciData->Status & PCI_STATUS_DEVSEL) == 0x400) DbgPrint(" slow devsel,");
|
|
if ((PciData->Status & PCI_STATUS_DEVSEL) == 0x600) DbgPrint(" unknown devsel,");
|
|
DbgPrint(" latency %d", PciData->LatencyTimer);
|
|
if (PciData->u.type0.InterruptPin != 0 &&
|
|
PciData->u.type0.InterruptLine != 0 &&
|
|
PciData->u.type0.InterruptLine != 0xFF) DbgPrint(", IRQ %02d", PciData->u.type0.InterruptLine);
|
|
else if (PciData->u.type0.InterruptPin != 0) DbgPrint(", IRQ assignment required");
|
|
DbgPrint("\n");
|
|
|
|
if (HeaderType == PCI_BRIDGE_TYPE)
|
|
{
|
|
DbgPrint("\tBridge:");
|
|
DbgPrint(" primary bus %d,", PciData->u.type1.PrimaryBus);
|
|
DbgPrint(" secondary bus %d,", PciData->u.type1.SecondaryBus);
|
|
DbgPrint(" subordinate bus %d,", PciData->u.type1.SubordinateBus);
|
|
DbgPrint(" secondary latency %d", PciData->u.type1.SecondaryLatency);
|
|
DbgPrint("\n");
|
|
}
|
|
|
|
/* Scan addresses */
|
|
Size = 0;
|
|
for (b = 0; b < (HeaderType == PCI_DEVICE_TYPE ? PCI_TYPE0_ADDRESSES : PCI_TYPE1_ADDRESSES); b++)
|
|
{
|
|
/* Check for a BAR */
|
|
if (HeaderType != PCI_CARDBUS_BRIDGE_TYPE)
|
|
Mem = PciData->u.type0.BaseAddresses[b];
|
|
else
|
|
Mem = 0;
|
|
if (Mem)
|
|
{
|
|
/* Decode the address type */
|
|
if (Mem & PCI_ADDRESS_IO_SPACE)
|
|
{
|
|
/* Guess the size */
|
|
Size = 1 << 2;
|
|
while (!(Mem & Size) && (Size)) Size <<= 1;
|
|
|
|
/* Print it out */
|
|
DbgPrint("\tI/O ports at %04lx", Mem & PCI_ADDRESS_IO_ADDRESS_MASK);
|
|
ShowSize(Size);
|
|
}
|
|
else
|
|
{
|
|
/* Guess the size */
|
|
Size = 1 << 8;
|
|
while (!(Mem & Size) && (Size)) Size <<= 1;
|
|
|
|
/* Print it out */
|
|
DbgPrint("\tMemory at %08lx (%d-bit, %sprefetchable)",
|
|
Mem & PCI_ADDRESS_MEMORY_ADDRESS_MASK,
|
|
(Mem & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_32BIT ? 32 : 64,
|
|
(Mem & PCI_ADDRESS_MEMORY_PREFETCHABLE) ? "" : "non-");
|
|
ShowSize(Size);
|
|
}
|
|
DbgPrint("\n");
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
CODE_SEG("INIT")
|
|
VOID
|
|
NTAPI
|
|
HalpInitializePciBus(VOID)
|
|
{
|
|
#ifndef _MINIHAL_
|
|
PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo;
|
|
UCHAR PciType;
|
|
PCI_SLOT_NUMBER PciSlot;
|
|
ULONG i, j, k;
|
|
UCHAR DataBuffer[PCI_COMMON_HDR_LENGTH];
|
|
PPCI_COMMON_CONFIG PciData = (PPCI_COMMON_CONFIG)DataBuffer;
|
|
PBUS_HANDLER BusHandler;
|
|
ULONG HackFlags;
|
|
BOOLEAN ExtendedAddressDecoding = FALSE;
|
|
NTSTATUS Status;
|
|
|
|
/* Query registry information */
|
|
PciRegistryInfo = HalpQueryPciRegistryInfo();
|
|
if (!PciRegistryInfo) return;
|
|
|
|
/* Initialize the PCI configuration lock */
|
|
KeInitializeSpinLock(&HalpPCIConfigLock);
|
|
|
|
/* Get the type and free the info structure */
|
|
PciType = PciRegistryInfo->HardwareMechanism & 0xF;
|
|
|
|
/* Check if this is a type 2 PCI bus with at least one bus */
|
|
if ((PciRegistryInfo->NoBuses) && (PciType == 2))
|
|
{
|
|
/* Setup the PCI slot */
|
|
PciSlot.u.bits.Reserved = 0;
|
|
PciSlot.u.bits.FunctionNumber = 0;
|
|
|
|
/* Loop all slots */
|
|
for (i = 0; i < 32; i++)
|
|
{
|
|
/* Try to setup a Type 2 PCI slot */
|
|
PciType = 2;
|
|
BusHandler = HalpAllocateAndInitPciBusHandler(2, 0, TRUE);
|
|
if (!BusHandler) break;
|
|
|
|
/* Now check if it's valid */
|
|
if (HalpIsValidPCIDevice(BusHandler, PciSlot)) break;
|
|
|
|
/* Heh, the BIOS lied... try Type 1 */
|
|
PciType = 1;
|
|
BusHandler = HalpAllocateAndInitPciBusHandler(1, 0, TRUE);
|
|
if (!BusHandler) break;
|
|
|
|
/* Now check if it's valid */
|
|
if (HalpIsValidPCIDevice(BusHandler, PciSlot)) break;
|
|
|
|
/* Keep trying */
|
|
PciType = 2;
|
|
}
|
|
|
|
/* Now allocate the correct kind of handler */
|
|
HalpAllocateAndInitPciBusHandler(PciType, 0, FALSE);
|
|
}
|
|
|
|
/* Okay, now loop all PCI bridges */
|
|
do
|
|
{
|
|
/* Loop all PCI buses */
|
|
for (i = 0; i < PciRegistryInfo->NoBuses; i++)
|
|
{
|
|
/* Check if we have a handler for it */
|
|
if (!HalHandlerForBus(PCIBus, i))
|
|
{
|
|
/* Allocate it */
|
|
HalpAllocateAndInitPciBusHandler(PciType, i, FALSE);
|
|
}
|
|
}
|
|
/* Go to the next bridge */
|
|
} while (HalpGetPciBridgeConfig(PciType, &PciRegistryInfo->NoBuses));
|
|
|
|
/* Now build correct address range informaiton */
|
|
HalpFixupPciSupportedRanges(PciRegistryInfo->NoBuses);
|
|
|
|
/* Loop every bus */
|
|
DbgPrint("\n====== PCI BUS HARDWARE DETECTION =======\n\n");
|
|
PciSlot.u.bits.Reserved = 0;
|
|
for (i = 0; i < PciRegistryInfo->NoBuses; i++)
|
|
{
|
|
/* Get the bus handler */
|
|
BusHandler = HalHandlerForBus(PCIBus, i);
|
|
|
|
/* Loop every device */
|
|
for (j = 0; j < 32; j++)
|
|
{
|
|
/* Loop every function */
|
|
PciSlot.u.bits.DeviceNumber = j;
|
|
for (k = 0; k < 8; k++)
|
|
{
|
|
/* Build the final slot structure */
|
|
PciSlot.u.bits.FunctionNumber = k;
|
|
|
|
/* Read the configuration information */
|
|
HalpReadPCIConfig(BusHandler,
|
|
PciSlot,
|
|
PciData,
|
|
0,
|
|
PCI_COMMON_HDR_LENGTH);
|
|
|
|
/* Skip if this is an invalid function */
|
|
if (PciData->VendorID == PCI_INVALID_VENDORID) continue;
|
|
|
|
/* Print out the entry */
|
|
HalpDebugPciDumpBus(i, j, k, PciData);
|
|
|
|
/* Check if this is a Cardbus bridge */
|
|
if (PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE)
|
|
{
|
|
/* Not supported */
|
|
DbgPrint("\tDevice is a PCI Cardbus Bridge. It will not work!\n");
|
|
continue;
|
|
}
|
|
|
|
/* Check if this is a PCI device */
|
|
if (PCI_CONFIGURATION_TYPE(PciData) != PCI_BRIDGE_TYPE)
|
|
{
|
|
/* Check if it has an interrupt pin and line registered */
|
|
if ((PciData->u.type1.InterruptPin) &&
|
|
(PciData->u.type1.InterruptLine))
|
|
{
|
|
/* Check if this interrupt line is connected to the bus */
|
|
if (PciData->u.type1.InterruptLine < 16)
|
|
{
|
|
/* Is this an IDE device? */
|
|
if (!HalpIsIdeDevice(PciData))
|
|
{
|
|
/* We'll mask out this interrupt then */
|
|
DbgPrint("\tDevice is using IRQ %d! ISA Cards using that IRQ may fail!\n",
|
|
PciData->u.type1.InterruptLine);
|
|
HalpPciIrqMask |= (1 << PciData->u.type1.InterruptLine);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Check for broken Intel chips */
|
|
if (PciData->VendorID == 0x8086)
|
|
{
|
|
/* Check for broken 82830 PCI controller */
|
|
if ((PciData->DeviceID == 0x04A3) &&
|
|
(PciData->RevisionID < 0x11))
|
|
{
|
|
/* Skip */
|
|
DbgPrint("\tDevice is a broken Intel 82430 PCI Controller. It will not work!\n\n");
|
|
continue;
|
|
}
|
|
|
|
/* Check for broken 82378 PCI-to-ISA Bridge */
|
|
if ((PciData->DeviceID == 0x0484) &&
|
|
(PciData->RevisionID <= 3))
|
|
{
|
|
/* Skip */
|
|
DbgPrint("\tDevice is a broken Intel 82378 PCI-to-ISA Bridge. It will not work!\n\n");
|
|
continue;
|
|
}
|
|
|
|
/* Check for broken 82450 PCI Bridge */
|
|
if ((PciData->DeviceID == 0x84C4) &&
|
|
(PciData->RevisionID <= 4))
|
|
{
|
|
DbgPrint("\tDevice is a Intel Orion 82450 PCI Bridge. It will not work!\n\n");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* Do we know this card? */
|
|
if (!ExtendedAddressDecoding)
|
|
{
|
|
/* Check for it */
|
|
if (HalpIsRecognizedCard(PciRegistryInfo,
|
|
PciData,
|
|
HALP_CARD_FEATURE_FULL_DECODE))
|
|
{
|
|
/* We'll do chipset checks later */
|
|
DbgPrint("\tDevice has Extended Address Decoding. It may fail to work on older BIOSes!\n");
|
|
ExtendedAddressDecoding = TRUE;
|
|
}
|
|
}
|
|
|
|
/* Now check the registry for chipset hacks */
|
|
Status = HalpGetChipHacks(PciData->VendorID,
|
|
PciData->DeviceID,
|
|
PciData->RevisionID,
|
|
&HackFlags);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Check for broken ACPI routing */
|
|
if (HackFlags & HAL_PCI_CHIP_HACK_DISABLE_ACPI_IRQ_ROUTING)
|
|
{
|
|
DbgPrint("This chipset has broken ACPI IRQ Routing! Be aware!\n\n");
|
|
continue;
|
|
}
|
|
|
|
/* Check for broken ACPI timer */
|
|
if (HackFlags & HAL_PCI_CHIP_HACK_BROKEN_ACPI_TIMER)
|
|
{
|
|
DbgPrint("This chipset has a broken ACPI timer! Be aware!\n\n");
|
|
continue;
|
|
}
|
|
|
|
/* Check for hibernate-disable */
|
|
if (HackFlags & HAL_PCI_CHIP_HACK_DISABLE_HIBERNATE)
|
|
{
|
|
DbgPrint("This chipset has a broken PCI device which is incompatible with hibernation. Be aware!\n\n");
|
|
continue;
|
|
}
|
|
|
|
/* Check for USB controllers that generate SMIs */
|
|
if (HackFlags & HAL_PCI_CHIP_HACK_USB_SMI_DISABLE)
|
|
{
|
|
DbgPrint("This chipset has a USB controller which generates SMIs. ReactOS will likely fail to boot!\n\n");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* Terminate the entry */
|
|
DbgPrint("\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Initialize NMI Crash Flag */
|
|
HalpGetNMICrashFlag();
|
|
|
|
/* Free the registry data */
|
|
ExFreePoolWithTag(PciRegistryInfo, TAG_HAL);
|
|
|
|
/* Tell PnP if this hard supports correct decoding */
|
|
HalpMarkChipsetDecode(ExtendedAddressDecoding);
|
|
DbgPrint("====== PCI BUS DETECTION COMPLETE =======\n\n");
|
|
#endif
|
|
}
|
|
|
|
#ifndef _MINIHAL_
|
|
CODE_SEG("INIT")
|
|
VOID
|
|
NTAPI
|
|
HalpInitBusHandlers(VOID)
|
|
{
|
|
/* Register the HAL Bus Handler support */
|
|
HalpRegisterInternalBusHandlers();
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
VOID
|
|
NTAPI
|
|
HalpRegisterKdSupportFunctions(VOID)
|
|
{
|
|
/* Register PCI Device Functions */
|
|
KdSetupPciDeviceForDebugging = HalpSetupPciDeviceForDebugging;
|
|
KdReleasePciDeviceforDebugging = HalpReleasePciDeviceForDebugging;
|
|
|
|
/* Register memory functions */
|
|
#ifndef _MINIHAL_
|
|
#if (NTDDI_VERSION >= NTDDI_VISTA)
|
|
KdMapPhysicalMemory64 = HalpMapPhysicalMemory64Vista;
|
|
KdUnmapVirtualAddress = HalpUnmapVirtualAddressVista;
|
|
#else
|
|
KdMapPhysicalMemory64 = HalpMapPhysicalMemory64;
|
|
KdUnmapVirtualAddress = HalpUnmapVirtualAddress;
|
|
#endif
|
|
#endif
|
|
|
|
/* Register ACPI stub */
|
|
KdCheckPowerButton = HalpCheckPowerButton;
|
|
}
|
|
#endif // _MINIHAL_
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
HalpAssignSlotResources(IN PUNICODE_STRING RegistryPath,
|
|
IN PUNICODE_STRING DriverClassName,
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN INTERFACE_TYPE BusType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG SlotNumber,
|
|
IN OUT PCM_RESOURCE_LIST *AllocatedResources)
|
|
{
|
|
PBUS_HANDLER Handler;
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
DPRINT1("Slot assignment for %d on bus %u\n", BusType, BusNumber);
|
|
|
|
/* Find the handler */
|
|
Handler = HalReferenceHandlerForBus(BusType, BusNumber);
|
|
if (!Handler) return STATUS_NOT_FOUND;
|
|
|
|
/* Do the assignment */
|
|
Status = Handler->AssignSlotResources(Handler,
|
|
Handler,
|
|
RegistryPath,
|
|
DriverClassName,
|
|
DriverObject,
|
|
DeviceObject,
|
|
SlotNumber,
|
|
AllocatedResources);
|
|
|
|
/* Dereference the handler and return */
|
|
HalDereferenceBusHandler(Handler);
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
HaliFindBusAddressTranslation(IN PHYSICAL_ADDRESS BusAddress,
|
|
IN OUT PULONG AddressSpace,
|
|
OUT PPHYSICAL_ADDRESS TranslatedAddress,
|
|
IN OUT PULONG_PTR Context,
|
|
IN BOOLEAN NextBus)
|
|
{
|
|
PHAL_BUS_HANDLER BusHandler;
|
|
PBUS_HANDLER Handler;
|
|
PLIST_ENTRY NextEntry;
|
|
ULONG ContextValue;
|
|
|
|
/* Make sure we have a context */
|
|
if (!Context) return FALSE;
|
|
ASSERT((*Context) || (NextBus == TRUE));
|
|
|
|
/* Read the context */
|
|
ContextValue = *Context;
|
|
|
|
/* Find the bus handler */
|
|
Handler = HalpContextToBusHandler(ContextValue);
|
|
if (!Handler) return FALSE;
|
|
|
|
/* Check if this is an ongoing lookup */
|
|
if (NextBus)
|
|
{
|
|
/* Get the HAL bus handler */
|
|
BusHandler = CONTAINING_RECORD(Handler, HAL_BUS_HANDLER, Handler);
|
|
NextEntry = &BusHandler->AllHandlers;
|
|
|
|
/* Get the next one if we were already with one */
|
|
if (ContextValue) NextEntry = NextEntry->Flink;
|
|
|
|
/* Start scanning */
|
|
while (TRUE)
|
|
{
|
|
/* Check if this is the last one */
|
|
if (NextEntry == &HalpAllBusHandlers)
|
|
{
|
|
/* Quit */
|
|
*Context = 1;
|
|
return FALSE;
|
|
}
|
|
|
|
/* Call this translator */
|
|
BusHandler = CONTAINING_RECORD(NextEntry, HAL_BUS_HANDLER, AllHandlers);
|
|
if (HalTranslateBusAddress(BusHandler->Handler.InterfaceType,
|
|
BusHandler->Handler.BusNumber,
|
|
BusAddress,
|
|
AddressSpace,
|
|
TranslatedAddress)) break;
|
|
|
|
/* Try the next one */
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
|
|
/* If we made it, we're done */
|
|
*Context = (ULONG_PTR)&BusHandler->Handler;
|
|
return TRUE;
|
|
}
|
|
|
|
/* Try the first one through */
|
|
if (!HalTranslateBusAddress(Handler->InterfaceType,
|
|
Handler->BusNumber,
|
|
BusAddress,
|
|
AddressSpace,
|
|
TranslatedAddress)) return FALSE;
|
|
|
|
/* Remember for next time */
|
|
*Context = (ULONG_PTR)Handler;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
HaliTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN PHYSICAL_ADDRESS BusAddress,
|
|
IN OUT PULONG AddressSpace,
|
|
OUT PPHYSICAL_ADDRESS TranslatedAddress)
|
|
{
|
|
PBUS_HANDLER Handler;
|
|
BOOLEAN Status;
|
|
|
|
/* Find the handler */
|
|
Handler = HalReferenceHandlerForBus(InterfaceType, BusNumber);
|
|
if (!(Handler) || !(Handler->TranslateBusAddress))
|
|
{
|
|
DPRINT1("No translator Interface: %x, Bus: %x, Handler: %p, BusAddress: %x!\n", InterfaceType, BusNumber, Handler, BusAddress);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Do the assignment */
|
|
Status = Handler->TranslateBusAddress(Handler,
|
|
Handler,
|
|
BusAddress,
|
|
AddressSpace,
|
|
TranslatedAddress);
|
|
|
|
/* Dereference the handler and return */
|
|
HalDereferenceBusHandler(Handler);
|
|
return Status;
|
|
}
|
|
|
|
/* PUBLIC FUNCTIONS **********************************************************/
|
|
|
|
#ifndef _MINIHAL_
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
HalAdjustResourceList(IN PIO_RESOURCE_REQUIREMENTS_LIST *ResourceList)
|
|
{
|
|
PBUS_HANDLER Handler;
|
|
ULONG Status;
|
|
PAGED_CODE();
|
|
|
|
/* Find the handler */
|
|
Handler = HalReferenceHandlerForBus((*ResourceList)->InterfaceType,
|
|
(*ResourceList)->BusNumber);
|
|
if (!Handler) return STATUS_SUCCESS;
|
|
|
|
/* Do the assignment */
|
|
Status = Handler->AdjustResourceList(Handler,
|
|
Handler,
|
|
ResourceList);
|
|
|
|
/* Dereference the handler and return */
|
|
HalDereferenceBusHandler(Handler);
|
|
return Status;
|
|
}
|
|
#endif // _MINIHAL_
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
HalAssignSlotResources(IN PUNICODE_STRING RegistryPath,
|
|
IN PUNICODE_STRING DriverClassName,
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN INTERFACE_TYPE BusType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG SlotNumber,
|
|
IN OUT PCM_RESOURCE_LIST *AllocatedResources)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
/* Check the bus type */
|
|
if (BusType != PCIBus)
|
|
{
|
|
/* Call our internal handler */
|
|
return HalpAssignSlotResources(RegistryPath,
|
|
DriverClassName,
|
|
DriverObject,
|
|
DeviceObject,
|
|
BusType,
|
|
BusNumber,
|
|
SlotNumber,
|
|
AllocatedResources);
|
|
}
|
|
else
|
|
{
|
|
/* Call the PCI registered function */
|
|
return HalPciAssignSlotResources(RegistryPath,
|
|
DriverClassName,
|
|
DriverObject,
|
|
DeviceObject,
|
|
PCIBus,
|
|
BusNumber,
|
|
SlotNumber,
|
|
AllocatedResources);
|
|
}
|
|
}
|
|
|
|
#ifndef _MINIHAL_
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ULONG
|
|
NTAPI
|
|
HalGetBusData(IN BUS_DATA_TYPE BusDataType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG SlotNumber,
|
|
IN PVOID Buffer,
|
|
IN ULONG Length)
|
|
{
|
|
/* Call the extended function */
|
|
return HalGetBusDataByOffset(BusDataType,
|
|
BusNumber,
|
|
SlotNumber,
|
|
Buffer,
|
|
0,
|
|
Length);
|
|
}
|
|
#endif // _MINIHAL_
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ULONG
|
|
NTAPI
|
|
HalGetBusDataByOffset(IN BUS_DATA_TYPE BusDataType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG SlotNumber,
|
|
IN PVOID Buffer,
|
|
IN ULONG Offset,
|
|
IN ULONG Length)
|
|
{
|
|
PBUS_HANDLER Handler;
|
|
ULONG Status;
|
|
|
|
/* Find the handler */
|
|
Handler = HaliReferenceHandlerForConfigSpace(BusDataType, BusNumber);
|
|
if (!Handler) return 0;
|
|
|
|
/* Do the assignment */
|
|
Status = Handler->GetBusData(Handler,
|
|
Handler,
|
|
SlotNumber,
|
|
Buffer,
|
|
Offset,
|
|
Length);
|
|
|
|
/* Dereference the handler and return */
|
|
HalDereferenceBusHandler(Handler);
|
|
return Status;
|
|
}
|
|
|
|
#ifndef _MINIHAL_
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ULONG
|
|
NTAPI
|
|
HalGetInterruptVector(IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG BusInterruptLevel,
|
|
IN ULONG BusInterruptVector,
|
|
OUT PKIRQL Irql,
|
|
OUT PKAFFINITY Affinity)
|
|
{
|
|
PBUS_HANDLER Handler;
|
|
ULONG Vector;
|
|
PAGED_CODE();
|
|
|
|
/* Defaults */
|
|
*Irql = 0;
|
|
*Affinity = 0;
|
|
|
|
/* Find the handler */
|
|
Handler = HalReferenceHandlerForBus(InterfaceType, BusNumber);
|
|
if (!Handler) return 0;
|
|
|
|
/* Do the assignment */
|
|
Vector = Handler->GetInterruptVector(Handler,
|
|
Handler,
|
|
BusInterruptLevel,
|
|
BusInterruptVector,
|
|
Irql,
|
|
Affinity);
|
|
if ((Vector != IRQ2VECTOR(BusInterruptLevel)) ||
|
|
(*Irql != VECTOR2IRQL(IRQ2VECTOR(BusInterruptLevel))))
|
|
{
|
|
DPRINT1("Returning IRQL %lx, Vector %lx for Level/Vector: %lx/%lx\n",
|
|
*Irql, Vector, BusInterruptLevel, BusInterruptVector);
|
|
DPRINT1("Old HAL would've returned IRQL %lx and Vector %lx\n",
|
|
VECTOR2IRQL(IRQ2VECTOR(BusInterruptLevel)),
|
|
IRQ2VECTOR(BusInterruptLevel));
|
|
}
|
|
|
|
/* Dereference the handler and return */
|
|
HalDereferenceBusHandler(Handler);
|
|
return Vector;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ULONG
|
|
NTAPI
|
|
HalSetBusData(IN BUS_DATA_TYPE BusDataType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG SlotNumber,
|
|
IN PVOID Buffer,
|
|
IN ULONG Length)
|
|
{
|
|
/* Call the extended function */
|
|
return HalSetBusDataByOffset(BusDataType,
|
|
BusNumber,
|
|
SlotNumber,
|
|
Buffer,
|
|
0,
|
|
Length);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ULONG
|
|
NTAPI
|
|
HalSetBusDataByOffset(IN BUS_DATA_TYPE BusDataType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG SlotNumber,
|
|
IN PVOID Buffer,
|
|
IN ULONG Offset,
|
|
IN ULONG Length)
|
|
{
|
|
PBUS_HANDLER Handler;
|
|
ULONG Status;
|
|
|
|
/* Find the handler */
|
|
Handler = HaliReferenceHandlerForConfigSpace(BusDataType, BusNumber);
|
|
if (!Handler) return 0;
|
|
|
|
/* Do the assignment */
|
|
Status = Handler->SetBusData(Handler,
|
|
Handler,
|
|
SlotNumber,
|
|
Buffer,
|
|
Offset,
|
|
Length);
|
|
|
|
/* Dereference the handler and return */
|
|
HalDereferenceBusHandler(Handler);
|
|
return Status;
|
|
}
|
|
#endif // _MINIHAL_
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOLEAN
|
|
NTAPI
|
|
HalTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
|
|
IN ULONG BusNumber,
|
|
IN PHYSICAL_ADDRESS BusAddress,
|
|
IN OUT PULONG AddressSpace,
|
|
OUT PPHYSICAL_ADDRESS TranslatedAddress)
|
|
{
|
|
/* Look as the bus type */
|
|
if (InterfaceType == PCIBus)
|
|
{
|
|
/* Call the PCI registered function */
|
|
return HalPciTranslateBusAddress(PCIBus,
|
|
BusNumber,
|
|
BusAddress,
|
|
AddressSpace,
|
|
TranslatedAddress);
|
|
}
|
|
else
|
|
{
|
|
/* Call the bus handler */
|
|
return HaliTranslateBusAddress(InterfaceType,
|
|
BusNumber,
|
|
BusAddress,
|
|
AddressSpace,
|
|
TranslatedAddress);
|
|
}
|
|
}
|
|
|
|
/* EOF */
|