// // fit bridge [checked] // VOID PciFitBridge(__in PPCI_FDO_EXTENSION ParentFdoExt,__in PPCI_PDO_EXTENSION BridgePdoExt) { PAGED_CODE(); UCHAR Lowest = 0xff; UCHAR MaxGaps = 0; UCHAR SecondaryBusForMaxGaps = 0; PPCI_PDO_EXTENSION BridgeExt = ParentFdoExt->ChildBridgePdoList; while(BridgeExt) { if(BridgeExt->NotPresent) { PciDebugPrintf(0x100000,"Skipping not present bridge PDOX @ %p\n",BridgeExt); } else if(PciAreBusNumbersConfigured(BridgeExt)) { UCHAR BaseBus = BridgeExt->Dependent.type1.SubordinateBus; UCHAR Limit = PciFindBridgeNumberLimit(ParentFdoExt,BaseBus); ASSERT(Limit >= BaseBus); if(Limit - BaseBus > MaxGaps) { ASSERT(Limit > BaseBus); MaxGaps = Limit - BaseBus; SecondaryBusForMaxGaps = BaseBus + 1; } if(BridgeExt->Dependent.type1.SecondaryBus < Lowest) Lowest = BridgeExt->Dependent.type1.SecondaryBus; } BridgeExt = BridgeExt->NextBridge; } ASSERT(Lowest > ParentFdoExt->BaseBus); UCHAR Gaps = 0; UCHAR SecondaryBus = 0; if(Lowest - ParentFdoExt->BaseBus - 1 <= MaxGaps) { Gaps = MaxGaps; SecondaryBus = SecondaryBusForMaxGaps; } else { SecondaryBus = ParentFdoExt->BaseBus + 1; Gaps = Lowest - ParentFdoExt->BaseBus - 1; } if(Gaps >= 1) { SecondaryBus = static_cast<UCHAR>(SecondaryBus + Gaps / 2); PciSetBusNumbers(BridgePdoExt,ParentFdoExt->BaseBus,SecondaryBus,SecondaryBus); PciUpdateAncestorSubordinateBuses(ParentFdoExt,BridgePdoExt->Dependent.type1.SecondaryBus); } }
// // find bridge limit worker [checked] // UCHAR PciFindBridgeNumberLimitWorker(__in PPCI_FDO_EXTENSION StartFdoExt,__in PPCI_FDO_EXTENSION CurFdoExt,__in UCHAR BaseBus,__out PBOOLEAN Include) { PAGED_CODE(); if(CurFdoExt != StartFdoExt) { KeEnterCriticalRegion(); KeWaitForSingleObject(&CurFdoExt->ChildListLock,Executive,KernelMode,FALSE,0); } PPCI_PDO_EXTENSION ChildBridgeExt = CurFdoExt->ChildBridgePdoList; UCHAR Limit = 0; if(ChildBridgeExt) { while(ChildBridgeExt) { if(ChildBridgeExt->NotPresent) { PciDebugPrintf(0x100000,"Skipping not present bridge PDOX @ %p\n",ChildBridgeExt); } else if(PciAreBusNumbersConfigured(ChildBridgeExt)) { if(ChildBridgeExt->Dependent.type1.SecondaryBus > BaseBus && (ChildBridgeExt->Dependent.type1.SecondaryBus < Limit || !Limit)) Limit = ChildBridgeExt->Dependent.type1.SecondaryBus; } ChildBridgeExt = ChildBridgeExt->NextBridge; } } if(Limit) { *Include = FALSE; } else { if(CurFdoExt->ParentFdoExtension) { Limit = PciFindBridgeNumberLimitWorker(StartFdoExt,CurFdoExt->ParentFdoExtension,BaseBus,Include); } else { Limit = CurFdoExt->MaxSubordinateBus; *Include = TRUE; } } if(CurFdoExt != StartFdoExt) { KeSetEvent(&CurFdoExt->ChildListLock,IO_NO_INCREMENT,FALSE); KeLeaveCriticalRegion(); } return Limit; }
// // spread bridges [checked] // VOID PciSpreadBridges(__in PPCI_FDO_EXTENSION ParentFdoExt,__in ULONG BridgeCount) { PAGED_CODE(); ASSERT(ParentFdoExt->BaseBus < PCI_MAX_BRIDGE_NUMBER); UCHAR BaseBus = ParentFdoExt->BaseBus; UCHAR Limit = PciFindBridgeNumberLimit(ParentFdoExt,BaseBus); ASSERT(Limit >= BaseBus); UCHAR Gaps = Limit - BaseBus; if(!Gaps) return; UCHAR Step = static_cast<UCHAR>(BridgeCount < Gaps ? Gaps / (BridgeCount + 1) : 1); UCHAR SecondaryBus = BaseBus + 1; UCHAR MaxAssigned = 0; PPCI_PDO_EXTENSION BridgeExt = ParentFdoExt->ChildBridgePdoList; while(BridgeExt) { if(BridgeExt->NotPresent) { PciDebugPrintf(0x100000,"Skipping not present bridge PDOX @ %p\n",BridgeExt); } else { ASSERT(!PciAreBusNumbersConfigured(BridgeExt)); PciSetBusNumbers(BridgeExt,BaseBus,SecondaryBus,SecondaryBus); MaxAssigned = SecondaryBus; if(static_cast<ULONG>(SecondaryBus) + static_cast<ULONG>(Step) < static_cast<ULONG>(SecondaryBus)) break; if(static_cast<ULONG>(SecondaryBus) + static_cast<ULONG>(Step) > static_cast<ULONG>(Limit)) break; SecondaryBus = SecondaryBus + Step; } BridgeExt = BridgeExt->NextBridge; } ASSERT(MaxAssigned); PciUpdateAncestorSubordinateBuses(ParentFdoExt,MaxAssigned); }
NTSTATUS NTAPI PciAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject) { PCM_RESOURCE_LIST Descriptor; PDEVICE_OBJECT AttachedTo; PPCI_FDO_EXTENSION FdoExtension; PPCI_FDO_EXTENSION ParentExtension; PPCI_PDO_EXTENSION PdoExtension; PDEVICE_OBJECT DeviceObject; UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)]; PKEY_VALUE_PARTIAL_INFORMATION ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer; NTSTATUS Status; HANDLE KeyHandle; UNICODE_STRING ValueName; ULONG ResultLength; PAGED_CODE(); DPRINT1("PCI - AddDevice (a new bus). PDO: %p (Driver: %wZ)\n", PhysicalDeviceObject, &PhysicalDeviceObject->DriverObject->DriverName); /* Zero out variables so failure path knows what to do */ AttachedTo = NULL; FdoExtension = NULL; PdoExtension = NULL; DeviceObject = NULL; do { /* Check if there's already a device extension for this bus */ ParentExtension = PciFindParentPciFdoExtension(PhysicalDeviceObject, &PciGlobalLock); if (ParentExtension) { /* Make sure we find a real PDO */ PdoExtension = PhysicalDeviceObject->DeviceExtension; ASSERT_PDO(PdoExtension); /* Make sure it's a PCI-to-PCI bridge */ if ((PdoExtension->BaseClass != PCI_CLASS_BRIDGE_DEV) || (PdoExtension->SubClass != PCI_SUBCLASS_BR_PCI_TO_PCI)) { /* This should never happen */ DPRINT1("PCI - PciAddDevice for Non-Root/Non-PCI-PCI bridge,\n" " Class %02x, SubClass %02x, will not add.\n", PdoExtension->BaseClass, PdoExtension->SubClass); ASSERT((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) && (PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI)); /* Enter the failure path */ Status = STATUS_INVALID_DEVICE_REQUEST; break; } /* Subordinate bus on the bridge */ DPRINT1("PCI - AddDevice (new bus is child of bus 0x%x).\n", ParentExtension->BaseBus); /* Make sure PCI bus numbers are configured */ if (!PciAreBusNumbersConfigured(PdoExtension)) { /* This is a critical failure */ DPRINT1("PCI - Bus numbers not configured for bridge (0x%x.0x%x.0x%x)\n", ParentExtension->BaseBus, PdoExtension->Slot.u.bits.DeviceNumber, PdoExtension->Slot.u.bits.FunctionNumber); /* Enter the failure path */ Status = STATUS_INVALID_DEVICE_REQUEST; break; } } /* Create the FDO for the bus */ Status = IoCreateDevice(DriverObject, sizeof(PCI_FDO_EXTENSION), NULL, FILE_DEVICE_BUS_EXTENDER, 0, 0, &DeviceObject); if (!NT_SUCCESS(Status)) break; /* Initialize the extension for the FDO */ FdoExtension = DeviceObject->DeviceExtension; PciInitializeFdoExtensionCommonFields(DeviceObject->DeviceExtension, DeviceObject, PhysicalDeviceObject); /* Attach to the root PDO */ Status = STATUS_NO_SUCH_DEVICE; AttachedTo = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject); ASSERT(AttachedTo != NULL); if (!AttachedTo) break; FdoExtension->AttachedDeviceObject = AttachedTo; /* Check if this is a child bus, or the root */ if (ParentExtension) { /* The child inherits root data */ FdoExtension->BaseBus = PdoExtension->Dependent.type1.SecondaryBus; FdoExtension->BusRootFdoExtension = ParentExtension->BusRootFdoExtension; PdoExtension->BridgeFdoExtension = FdoExtension; FdoExtension->ParentFdoExtension = ParentExtension; } else { /* Query the boot configuration */ Status = PciGetDeviceProperty(PhysicalDeviceObject, DevicePropertyBootConfiguration, (PVOID*)&Descriptor); if (!NT_SUCCESS(Status)) { /* No configuration has been set */ Descriptor = NULL; } else { /* Root PDO in ReactOS does not assign boot resources */ UNIMPLEMENTED_DBGBREAK("Encountered during setup\n"); Descriptor = NULL; } if (Descriptor) { /* Root PDO in ReactOS does not assign boot resources */ UNIMPLEMENTED_DBGBREAK(); } else { /* Default configuration isn't the normal path on Windows */ if (PciBreakOnDefault) { /* If a second bus is found and there's still no data, crash */ KeBugCheckEx(PCI_BUS_DRIVER_INTERNAL, 0xDEAD0010u, (ULONG_PTR)DeviceObject, 0, 0); } /* Warn that a default configuration will be used, and set bus 0 */ DPRINT1("PCI Will use default configuration.\n"); PciBreakOnDefault = TRUE; FdoExtension->BaseBus = 0; } /* This is the root bus */ FdoExtension->BusRootFdoExtension = FdoExtension; } /* Get the HAL or ACPI Bus Handler Callbacks for Configuration Access */ Status = PciGetConfigHandlers(FdoExtension); if (!NT_SUCCESS(Status)) break; /* Initialize all the supported PCI arbiters */ Status = PciInitializeArbiters(FdoExtension); if (!NT_SUCCESS(Status)) break; /* This is a real FDO, insert it into the list */ FdoExtension->Fake = FALSE; PciInsertEntryAtTail(&PciFdoExtensionListHead, FdoExtension, &PciGlobalLock); /* Open the device registry key so that we can query the errata flags */ IoOpenDeviceRegistryKey(DeviceObject, PLUGPLAY_REGKEY_DEVICE, KEY_ALL_ACCESS, &KeyHandle), /* Open the value that contains errata flags for this bus instance */ RtlInitUnicodeString(&ValueName, L"HackFlags"); Status = ZwQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, ValueInfo, sizeof(Buffer), &ResultLength); ZwClose(KeyHandle); if (NT_SUCCESS(Status)) { /* Make sure the data is of expected type and size */ if ((ValueInfo->Type == REG_DWORD) && (ValueInfo->DataLength == sizeof(ULONG))) { /* Read the flags for this bus */ FdoExtension->BusHackFlags = *(PULONG)&ValueInfo->Data; } } /* Query ACPI for PCI HotPlug Support */ PciGetHotPlugParameters(FdoExtension); /* The Bus FDO is now initialized */ DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; return STATUS_SUCCESS; } while (FALSE); /* This is the failure path */ ASSERT(!NT_SUCCESS(Status)); /* Check if the FDO extension exists */ if (FdoExtension) DPRINT1("Should destroy secondaries\n"); /* Delete device objects */ if (AttachedTo) IoDetachDevice(AttachedTo); if (DeviceObject) IoDeleteDevice(DeviceObject); return Status; }
// // configure bus numbers [checked] // VOID PciConfigureBusNumbers(__in PPCI_FDO_EXTENSION FdoExt) { PAGED_CODE(); PPCI_PDO_EXTENSION PdoExt = 0; if(FdoExt != FdoExt->BusRootFdoExtension) PdoExt = static_cast<PPCI_PDO_EXTENSION>(FdoExt->PhysicalDeviceObject->DeviceExtension); KeEnterCriticalRegion(); KeWaitForSingleObject(&FdoExt->ChildListLock,Executive,KernelMode,FALSE,0); PPCI_PDO_EXTENSION BridgeExt = FdoExt->ChildBridgePdoList; ULONG BridgeCount = 0; ULONG ConfiguredBridgeCount = 0; while(BridgeExt) { if(BridgeExt->NotPresent) { PciDebugPrintf(0x100000,"Skipping not present bridge PDOX @ %p\n",BridgeExt); } else { BridgeCount += 1; if((!PdoExt || !PdoExt->Dependent.type1.WeChangedBusNumbers || BridgeExt->Common.DeviceState != PciNotStarted) && PciAreBusNumbersConfigured(BridgeExt)) ConfiguredBridgeCount += 1; else PciDisableBridge(BridgeExt); } BridgeExt = BridgeExt->NextBridge; } KeSetEvent(&FdoExt->ChildListLock,IO_NO_INCREMENT,FALSE); KeLeaveCriticalRegion(); if(!BridgeCount) { PciDebugPrintf(0x100000,"PCI - No bridges found on bus 0x%x\n",FdoExt->BaseBus); return; } if(BridgeCount == ConfiguredBridgeCount) { PciDebugPrintf(0x100000,"PCI - 0x%x bridges found on bus 0x%x - all already configured\n",BridgeCount,FdoExt->BaseBus); return; } if(!ConfiguredBridgeCount) { PciDebugPrintf(0x100000,"PCI - 0x%x bridges found on bus 0x%x - all need configuration\n",BridgeCount,FdoExt->BaseBus); return PciSpreadBridges(FdoExt,BridgeCount); } ASSERT(ConfiguredBridgeCount < BridgeCount); PciDebugPrintf(0x100000,"PCI - 0x%x bridges found on bus 0x%x - 0x%x need configuration\n",BridgeCount,FdoExt->BaseBus,BridgeCount - ConfiguredBridgeCount); BridgeExt = FdoExt->ChildBridgePdoList; while(BridgeExt) { if(BridgeExt->NotPresent) { PciDebugPrintf(0x100000,"Skipping not present bridge PDOX @ %p\n",BridgeExt); } else { if((PdoExt && PdoExt->Dependent.type1.WeChangedBusNumbers && BridgeExt->Common.DeviceState == PciNotStarted) || !PciAreBusNumbersConfigured(BridgeExt)) { ASSERT(!BridgeExt->Dependent.type1.PrimaryBus && !BridgeExt->Dependent.type1.SecondaryBus && !BridgeExt->Dependent.type1.SubordinateBus); PciFitBridge(FdoExt,PdoExt); } } BridgeExt = BridgeExt->NextBridge; } }