INIT_FUNCTION 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))); }
PHYSICAL_ADDRESS NTAPI PciBridgePrefetchMemoryBase(IN PPCI_COMMON_HEADER PciData) { BOOLEAN Is64Bit; LARGE_INTEGER Base; USHORT PrefetchBase; ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE); /* Get the base */ PrefetchBase = PciData->u.type1.PrefetchBase; /* Low bit specifies 64-bit address, top bits specify the base */ Is64Bit = (PrefetchBase & 0xF) == 1; Base.LowPart = ((PrefetchBase & 0xFFF0) << 16); /* Is it 64-bit? */ if (Is64Bit) { /* Read the upper 32-bits from the other register */ Base.HighPart = PciData->u.type1.PrefetchBaseUpper32; } /* Return the base */ return Base; }
ULONG NTAPI PciBridgeIoLimit(IN PPCI_COMMON_HEADER PciData) { BOOLEAN Is32Bit; ULONG Limit, IoLimit; ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE); /* Get the limit */ Limit = PciData->u.type1.IOLimit; /* Low bit specifies 32-bit address, top bits specify the limit */ Is32Bit = (Limit & 0xF) == 1; IoLimit = (Limit & 0xF0) << 8; /* Is it 32-bit? */ if (Is32Bit) { /* Read the upper 16-bits from the other register */ IoLimit |= PciData->u.type1.IOLimitUpper16 << 16; ASSERT(PciData->u.type1.IOBase & 0x1); } /* Return the I/O limit */ return IoLimit | 0xFFF; }
INIT_FUNCTION 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; }
ULONG NTAPI PciBridgeMemoryLimit(IN PPCI_COMMON_HEADER PciData) { ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE); /* Return the memory limit */ return (PciData->u.type1.MemoryLimit << 16) | 0xFFFFF; }
ULONG NTAPI PciBridgeMemoryBase(IN PPCI_COMMON_HEADER PciData) { ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE); /* Return the memory base */ return (PciData->u.type1.MemoryBase << 16); }
INIT_FUNCTION 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 }
INIT_FUNCTION 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; }