Sync with trunk r58740.
[reactos.git] / drivers / bus / pcix / fdo.c
index f4d3095..fbb6971 100644 (file)
 
 /* GLOBALS ********************************************************************/
 
+SINGLE_LIST_ENTRY PciFdoExtensionListHead;
+BOOLEAN PciBreakOnDefault;
+
+PCI_MN_DISPATCH_TABLE PciFdoDispatchPowerTable[] =
+{
+    {IRP_DISPATCH, (PCI_DISPATCH_FUNCTION)PciFdoWaitWake},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoSetPowerState},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryPower},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported}
+};
+
+PCI_MN_DISPATCH_TABLE PciFdoDispatchPnpTable[] =
+{
+    {IRP_UPWARD,   (PCI_DISPATCH_FUNCTION)PciFdoIrpStartDevice},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryRemoveDevice},
+    {IRP_DISPATCH, (PCI_DISPATCH_FUNCTION)PciFdoIrpRemoveDevice},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpCancelRemoveDevice},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpStopDevice},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryStopDevice},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpCancelStopDevice},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryDeviceRelations},
+    {IRP_DISPATCH, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryInterface},
+    {IRP_UPWARD,   (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryCapabilities},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported},
+    {IRP_UPWARD,   (PCI_DISPATCH_FUNCTION)PciFdoIrpDeviceUsageNotification},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpSurpriseRemoval},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciFdoIrpQueryLegacyBusInformation},
+    {IRP_DOWNWARD, (PCI_DISPATCH_FUNCTION)PciIrpNotSupported}
+};
+
+PCI_MJ_DISPATCH_TABLE PciFdoDispatchTable =
+{
+    IRP_MN_QUERY_LEGACY_BUS_INFORMATION,
+    PciFdoDispatchPnpTable,
+    IRP_MN_QUERY_POWER,
+    PciFdoDispatchPowerTable,
+    IRP_DOWNWARD,
+    (PCI_DISPATCH_FUNCTION)PciIrpNotSupported,
+    IRP_DOWNWARD,
+    (PCI_DISPATCH_FUNCTION)PciIrpNotSupported
+};
+
 /* FUNCTIONS ******************************************************************/
 
+NTSTATUS
+NTAPI
+PciFdoIrpStartDevice(IN PIRP Irp,
+                     IN PIO_STACK_LOCATION IoStackLocation,
+                     IN PPCI_FDO_EXTENSION DeviceExtension)
+{
+    NTSTATUS Status;
+    PCM_RESOURCE_LIST Resources;
+    PAGED_CODE();
+
+    /* The device stack must be starting the FDO in a success path */
+    if (!NT_SUCCESS(Irp->IoStatus.Status)) return STATUS_NOT_SUPPORTED;
+
+    /* Attempt to switch the state machine to the started state */
+    Status = PciBeginStateTransition(DeviceExtension, PciStarted);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Check for any boot-provided resources */
+    Resources = IoStackLocation->Parameters.StartDevice.AllocatedResources;
+    if ((Resources) && !(PCI_IS_ROOT_FDO(DeviceExtension)))
+    {
+        /* These resources would only be for non-root FDOs, unhandled for now */
+        ASSERT(Resources->Count == 1);
+        UNIMPLEMENTED_DBGBREAK();
+    }
+
+    /* Initialize the arbiter for this FDO */
+    Status = PciInitializeArbiterRanges(DeviceExtension, Resources);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Cancel the transition if this failed */
+        PciCancelStateTransition(DeviceExtension, PciStarted);
+        return Status;
+    }
+
+    /* Again, check for boot-provided resources for non-root FDO */
+    if ((Resources) && !(PCI_IS_ROOT_FDO(DeviceExtension)))
+    {
+        /* Unhandled for now */
+        ASSERT(Resources->Count == 1);
+        UNIMPLEMENTED_DBGBREAK();
+    }
+
+    /* Commit the transition to the started state */
+    PciCommitStateTransition(DeviceExtension, PciStarted);
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+PciFdoIrpQueryRemoveDevice(IN PIRP Irp,
+                           IN PIO_STACK_LOCATION IoStackLocation,
+                           IN PPCI_FDO_EXTENSION DeviceExtension)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS
+NTAPI
+PciFdoIrpRemoveDevice(IN PIRP Irp,
+                      IN PIO_STACK_LOCATION IoStackLocation,
+                      IN PPCI_FDO_EXTENSION DeviceExtension)
+{
+    UNIMPLEMENTED_DBGBREAK();
+    return STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS
+NTAPI
+PciFdoIrpCancelRemoveDevice(IN PIRP Irp,
+                            IN PIO_STACK_LOCATION IoStackLocation,
+                            IN PPCI_FDO_EXTENSION DeviceExtension)
+{
+    UNIMPLEMENTED_DBGBREAK();
+    return STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS
+NTAPI
+PciFdoIrpStopDevice(IN PIRP Irp,
+                    IN PIO_STACK_LOCATION IoStackLocation,
+                    IN PPCI_FDO_EXTENSION DeviceExtension)
+{
+    UNIMPLEMENTED_DBGBREAK();
+    return STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS
+NTAPI
+PciFdoIrpQueryStopDevice(IN PIRP Irp,
+                         IN PIO_STACK_LOCATION IoStackLocation,
+                         IN PPCI_FDO_EXTENSION DeviceExtension)
+{
+    UNIMPLEMENTED_DBGBREAK();
+    return STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS
+NTAPI
+PciFdoIrpCancelStopDevice(IN PIRP Irp,
+                          IN PIO_STACK_LOCATION IoStackLocation,
+                          IN PPCI_FDO_EXTENSION DeviceExtension)
+{
+    UNIMPLEMENTED_DBGBREAK();
+    return STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS
+NTAPI
+PciFdoIrpQueryDeviceRelations(IN PIRP Irp,
+                              IN PIO_STACK_LOCATION IoStackLocation,
+                              IN PPCI_FDO_EXTENSION DeviceExtension)
+{
+    NTSTATUS Status;
+    PAGED_CODE();
+
+    /* Are bus relations being queried? */
+    if (IoStackLocation->Parameters.QueryDeviceRelations.Type != BusRelations)
+    {
+        /* The FDO is a bus, so only bus relations can be obtained */
+        Status = STATUS_NOT_SUPPORTED;
+    }
+    else
+    {
+        /* Scan the PCI bus and build the device relations for the caller */
+        Status = PciQueryDeviceRelations(DeviceExtension,
+                                         (PDEVICE_RELATIONS*)
+                                         &Irp->IoStatus.Information);
+    }
+
+    /* Return the enumeration status back */
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+PciFdoIrpQueryInterface(IN PIRP Irp,
+                        IN PIO_STACK_LOCATION IoStackLocation,
+                        IN PPCI_FDO_EXTENSION DeviceExtension)
+{
+    NTSTATUS Status;
+    PAGED_CODE();
+    ASSERT(DeviceExtension->ExtensionType == PciFdoExtensionType);
+
+    /* Deleted extensions don't respond to IRPs */
+    if (DeviceExtension->DeviceState == PciDeleted)
+    {
+        /* Hand it back to try to deal with it */
+        return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
+    }
+
+    /* Query our driver for this interface */
+    Status = PciQueryInterface(DeviceExtension,
+                               IoStackLocation->Parameters.QueryInterface.
+                               InterfaceType,
+                               IoStackLocation->Parameters.QueryInterface.
+                               Size,
+                               IoStackLocation->Parameters.QueryInterface.
+                               Version,
+                               IoStackLocation->Parameters.QueryInterface.
+                               InterfaceSpecificData,
+                               IoStackLocation->Parameters.QueryInterface.
+                               Interface,
+                               FALSE);
+    if (NT_SUCCESS(Status))
+    {
+        /* We found it, let the PDO handle it */
+        Irp->IoStatus.Status = Status;
+        return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
+    }
+    else if (Status == STATUS_NOT_SUPPORTED)
+    {
+        /* Otherwise, we can't handle it, let someone else down the stack try */
+        Status = PciCallDownIrpStack(DeviceExtension, Irp);
+        if (Status == STATUS_NOT_SUPPORTED)
+        {
+            /* They can't either, try a last-resort interface lookup */
+            Status = PciQueryInterface(DeviceExtension,
+                                       IoStackLocation->Parameters.QueryInterface.
+                                       InterfaceType,
+                                       IoStackLocation->Parameters.QueryInterface.
+                                       Size,
+                                       IoStackLocation->Parameters.QueryInterface.
+                                       Version,
+                                       IoStackLocation->Parameters.QueryInterface.
+                                       InterfaceSpecificData,
+                                       IoStackLocation->Parameters.QueryInterface.
+                                       Interface,
+                                       TRUE);
+        }
+    }
+
+    /* Has anyone claimed this interface yet? */
+    if (Status == STATUS_NOT_SUPPORTED)
+    {
+        /* No, return the original IRP status */
+        Status = Irp->IoStatus.Status;
+    }
+    else
+    {
+        /* Yes, set the new IRP status */
+        Irp->IoStatus.Status = Status;
+    }
+
+    /* Complete this IRP */
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+PciFdoIrpQueryCapabilities(IN PIRP Irp,
+                           IN PIO_STACK_LOCATION IoStackLocation,
+                           IN PPCI_FDO_EXTENSION DeviceExtension)
+{
+    PDEVICE_CAPABILITIES Capabilities;
+    PAGED_CODE();
+    ASSERT_FDO(DeviceExtension);
+
+    /* Get the capabilities */
+    Capabilities = IoStackLocation->Parameters.DeviceCapabilities.Capabilities;
+
+    /* Inherit wake levels and power mappings from the higher-up capabilities */
+    DeviceExtension->PowerState.SystemWakeLevel = Capabilities->SystemWake;
+    DeviceExtension->PowerState.DeviceWakeLevel = Capabilities->DeviceWake;
+    RtlCopyMemory(DeviceExtension->PowerState.SystemStateMapping,
+                  Capabilities->DeviceState,
+                  sizeof(DeviceExtension->PowerState.SystemStateMapping));
+
+    /* Dump the capabilities and return success */
+    PciDebugDumpQueryCapabilities(Capabilities);
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+PciFdoIrpDeviceUsageNotification(IN PIRP Irp,
+                                 IN PIO_STACK_LOCATION IoStackLocation,
+                                 IN PPCI_FDO_EXTENSION DeviceExtension)
+{
+    UNIMPLEMENTED_DBGBREAK();
+    return STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS
+NTAPI
+PciFdoIrpSurpriseRemoval(IN PIRP Irp,
+                         IN PIO_STACK_LOCATION IoStackLocation,
+                         IN PPCI_FDO_EXTENSION DeviceExtension)
+{
+    UNIMPLEMENTED_DBGBREAK();
+    return STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS
+NTAPI
+PciFdoIrpQueryLegacyBusInformation(IN PIRP Irp,
+                                   IN PIO_STACK_LOCATION IoStackLocation,
+                                   IN PPCI_FDO_EXTENSION DeviceExtension)
+{
+    UNIMPLEMENTED_DBGBREAK();
+    return STATUS_NOT_SUPPORTED;
+}
+
+VOID
+NTAPI
+PciGetHotPlugParameters(IN PPCI_FDO_EXTENSION FdoExtension)
+{
+    ACPI_EVAL_INPUT_BUFFER InputBuffer;
+    PACPI_EVAL_OUTPUT_BUFFER OutputBuffer;
+    ULONG Length;
+    NTSTATUS Status;
+    PAGED_CODE();
+
+    /* We should receive 4 parameters, per the HPP specification */
+    Length = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + 4 * sizeof(ACPI_METHOD_ARGUMENT);
+
+    /* Allocate the buffer to hold the parameters */
+    OutputBuffer = ExAllocatePoolWithTag(PagedPool, Length, PCI_POOL_TAG);
+    if (!OutputBuffer) return;
+
+    /* Initialize the output and input buffers. The method is _HPP */
+    RtlZeroMemory(OutputBuffer, Length);
+    *(PULONG)InputBuffer.MethodName = 'PPH_';
+    InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
+    do
+    {
+        /* Send the IOCTL to the ACPI driver */
+        Status = PciSendIoctl(FdoExtension->PhysicalDeviceObject,
+                              IOCTL_ACPI_EVAL_METHOD,
+                              &InputBuffer,
+                              sizeof(InputBuffer),
+                              OutputBuffer,
+                              Length);
+        if (!NT_SUCCESS(Status))
+        {
+            /* The method failed, check if we can salvage data from parent */
+            if (!PCI_IS_ROOT_FDO(FdoExtension))
+            {
+                /* Copy the root bus' hot plug parameters */
+                FdoExtension->HotPlugParameters = FdoExtension->ParentFdoExtension->HotPlugParameters;
+            }
+
+            /* Nothing more to do on this path */
+            break;
+        }
+
+        /* ACPI sent back some data. 4 parameters are expected in the output */
+        if (OutputBuffer->Count != 4) break;
+
+        /* HotPlug PCI Support not yet implemented */
+        UNIMPLEMENTED_DBGBREAK();
+    } while (FALSE);
+
+    /* Free the buffer and return */
+    ExFreePoolWithTag(OutputBuffer, 0);
+}
+
+VOID
+NTAPI
+PciInitializeFdoExtensionCommonFields(PPCI_FDO_EXTENSION FdoExtension,
+                                      IN PDEVICE_OBJECT DeviceObject,
+                                      IN PDEVICE_OBJECT PhysicalDeviceObject)
+{
+    /* Initialize the extension */
+    RtlZeroMemory(FdoExtension, sizeof(PCI_FDO_EXTENSION));
+
+    /* Setup the common fields */
+    FdoExtension->PhysicalDeviceObject = PhysicalDeviceObject;
+    FdoExtension->FunctionalDeviceObject = DeviceObject;
+    FdoExtension->ExtensionType = PciFdoExtensionType;
+    FdoExtension->PowerState.CurrentSystemState = PowerSystemWorking;
+    FdoExtension->PowerState.CurrentDeviceState = PowerDeviceD0;
+    FdoExtension->IrpDispatchTable = &PciFdoDispatchTable;
+
+    /* Initialize the extension locks */
+    KeInitializeEvent(&FdoExtension->SecondaryExtLock, SynchronizationEvent, TRUE);
+    KeInitializeEvent(&FdoExtension->ChildListLock, SynchronizationEvent, TRUE);
+
+    /* Initialize the default state */
+    PciInitializeState(FdoExtension);
+}
+
+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;
+    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;
+}
+
 /* EOF */