VOID HalpGetPciBridgeNeeds ( IN ULONG HwType, IN PUCHAR MaxPciBus, IN PCONFIGBRIDGE Current ) { ACCESS_MASK DesiredAccess; UNICODE_STRING unicodeString; PUCHAR buffer; HANDLE handle; OBJECT_ATTRIBUTES objectAttributes; PCM_FULL_RESOURCE_DESCRIPTOR Descriptor; PCONFIGURATION_COMPONENT Component; CONFIGBRIDGE CB; ULONG mnum, d, f; NTSTATUS status; buffer = ExAllocatePool (PagedPool, 1024); // init CB.PciData = (PPCI_COMMON_CONFIG) CB.Buffer; CB.SlotNumber.u.bits.Reserved = 0; Current->IO = Current->Memory = Current->PFMemory = 0; // // Assign this bridge an ID, and turn on configuration space // Current->PciData->u.type1.PrimaryBus = (UCHAR) Current->BusNo; Current->PciData->u.type1.SecondaryBus = (UCHAR) *MaxPciBus; Current->PciData->u.type1.SubordinateBus = (UCHAR) 0xFF; Current->PciData->u.type1.SecondaryStatus = 0xffff; Current->PciData->Status = 0xffff; Current->PciData->Command = 0; Current->PciData->u.type1.BridgeControl = PCI_ASSERT_BRIDGE_RESET; HalpWritePCIConfig ( Current->BusHandler, Current->SlotNumber, Current->PciData, 0, PCI_COMMON_HDR_LENGTH ); KeStallExecutionProcessor (100); Current->PciData->u.type1.BridgeControl = 0; HalpWritePCIConfig ( Current->BusHandler, Current->SlotNumber, Current->PciData, 0, PCI_COMMON_HDR_LENGTH ); KeStallExecutionProcessor (100); // // Allocate new handler for bus // CB.BusHandler = HalpAllocateAndInitPciBusHandler (HwType, *MaxPciBus, FALSE); CB.BusData = (PPCIPBUSDATA) CB.BusHandler->BusData; CB.BusNo = *MaxPciBus; *MaxPciBus += 1; // // Add another PCI bus in the registry // mnum = 0; for (; ;) { // // Find next available MultiFunctionAdapter key // DesiredAccess = KEY_READ | KEY_WRITE; swprintf ((PWCHAR) buffer, L"%s\\%d", rgzMultiFunctionAdapter, mnum); RtlInitUnicodeString (&unicodeString, (PWCHAR) buffer); InitializeObjectAttributes( &objectAttributes, &unicodeString, OBJ_CASE_INSENSITIVE, NULL, (PSECURITY_DESCRIPTOR) NULL ); status = ZwOpenKey( &handle, DesiredAccess, &objectAttributes); if (!NT_SUCCESS(status)) { break; } // already exists, next ZwClose (handle); mnum += 1; } ZwCreateKey (&handle, DesiredAccess, &objectAttributes, 0, NULL, REG_OPTION_VOLATILE, &d ); // // Add needed registry values for this MultifucntionAdapter entry // RtlInitUnicodeString (&unicodeString, rgzIdentifier); ZwSetValueKey (handle, &unicodeString, 0L, REG_SZ, L"PCI", sizeof (L"PCI") ); RtlInitUnicodeString (&unicodeString, rgzConfigurationData); Descriptor = (PCM_FULL_RESOURCE_DESCRIPTOR) buffer; Descriptor->InterfaceType = PCIBus; Descriptor->BusNumber = CB.BusNo; Descriptor->PartialResourceList.Version = 0; Descriptor->PartialResourceList.Revision = 0; Descriptor->PartialResourceList.Count = 0; ZwSetValueKey (handle, &unicodeString, 0L, REG_FULL_RESOURCE_DESCRIPTOR, Descriptor, sizeof (*Descriptor) ); RtlInitUnicodeString (&unicodeString, L"Component Information"); Component = (PCONFIGURATION_COMPONENT) buffer; RtlZeroMemory (Component, sizeof (*Component)); Component->AffinityMask = 0xffffffff; ZwSetValueKey (handle, &unicodeString, 0L, REG_BINARY, Component, FIELD_OFFSET (CONFIGURATION_COMPONENT, ConfigurationDataLength) ); ZwClose (handle); // // Since the firmware didn't configure this bridge we'll assume that // the PCI interrupts are bridged. // for (d = 0; d < PCI_MAX_DEVICES; d++) { CB.SlotNumber.u.bits.DeviceNumber = d; for (f = 0; f < PCI_MAX_FUNCTION; f++) { CB.SlotNumber.u.bits.FunctionNumber = f; HalpReadPCIConfig ( Current->BusHandler, CB.SlotNumber, CB.PciData, 0, PCI_COMMON_HDR_LENGTH ); if (CB.PciData->VendorID == PCI_INVALID_VENDORID) { break; } if (CB.PciData->u.type0.InterruptPin && (PCI_CONFIG_TYPE (CB.PciData) == PCI_DEVICE_TYPE || PCI_CONFIG_TYPE (CB.PciData) == PCI_BRIDGE_TYPE)) { // // Get IRQ value from table since firmware // did not initialize the bridge. // Current->PciData->u.type1.InterruptPin = CB.PciData->u.type0.InterruptPin + (UCHAR)d % 4; Current->PciData->u.type1.InterruptLine = HalpPCIPinToLineTable[(CB.BusNo*8) + CB.SlotNumber.u.bits.DeviceNumber]; } } } // // Look at each device on the bus and determine it's resource needs // for (d = 0; d < PCI_MAX_DEVICES; d++) { CB.SlotNumber.u.bits.DeviceNumber = d; for (f = 0; f < PCI_MAX_FUNCTION; f++) { CB.SlotNumber.u.bits.FunctionNumber = f; HalpReadPCIConfig ( CB.BusHandler, CB.SlotNumber, CB.PciData, 0, PCI_COMMON_HDR_LENGTH ); if (CB.PciData->VendorID == PCI_INVALID_VENDORID) { break; } if (IsPciBridge (CB.PciData)) { // oh look - another bridge ... HalpGetPciBridgeNeeds (HwType, MaxPciBus, &CB); continue; } if (PCI_CONFIG_TYPE (CB.PciData) != PCI_DEVICE_TYPE) { continue; } // found a device - figure out the resources it needs } } // // Found all sub-buses set SubordinateBus accordingly // Current->PciData->u.type1.SubordinateBus = (UCHAR) *MaxPciBus - 1; HalpWritePCIConfig ( Current->BusHandler, Current->SlotNumber, Current->PciData, 0, PCI_COMMON_HDR_LENGTH ); // // Set the bridges IO, Memory, and Prefetch Memory windows // // For now just pick some numbers & set everyone the same // IO 0x6000 - 0xFFFF // MEM 0x40000000 - 0x4FFFFFFF // PFMEM 0x50000000 - 0x5FFFFFFF Current->PciData->u.type1.IOBase = 0xD000 >> 12 << 4; Current->PciData->u.type1.IOLimit = 0xffff >> 12 << 4; Current->PciData->u.type1.MemoryBase = 0x0 >> 20 << 4; Current->PciData->u.type1.MemoryLimit = 0x0 >> 20 << 4; Current->PciData->u.type1.PrefetchBase = 0 >> 20 << 4; Current->PciData->u.type1.PrefetchLimit = 0 >> 20 << 4; Current->PciData->u.type1.PrefetchBaseUpper32 = 0; Current->PciData->u.type1.PrefetchLimitUpper32 = 0; Current->PciData->u.type1.IOBaseUpper16 = 0; Current->PciData->u.type1.IOLimitUpper16 = 0; Current->PciData->u.type1.BridgeControl = PCI_ENABLE_BRIDGE_ISA; HalpWritePCIConfig ( Current->BusHandler, Current->SlotNumber, Current->PciData, 0, PCI_COMMON_HDR_LENGTH ); HalpReadPCIConfig ( Current->BusHandler, Current->SlotNumber, Current->PciData, 0, PCI_COMMON_HDR_LENGTH ); // enable memory & io decodes Current->PciData->Command = PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE | PCI_ENABLE_BUS_MASTER; HalpWritePCIConfig ( Current->BusHandler, Current->SlotNumber, &Current->PciData->Command, FIELD_OFFSET (PCI_COMMON_CONFIG, Command), sizeof (Current->PciData->Command) ); ExFreePool (buffer); }
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 }