/*
 * PROJECT:         ReactOS PCI Bus Driver
 * LICENSE:         BSD - See COPYING.ARM in the top level directory
 * FILE:            drivers/bus/pci/pci/ppbridge.c
 * PURPOSE:         PCI-to-PCI Bridge Support
 * PROGRAMMERS:     ReactOS Portable Systems Group
 */

/* INCLUDES *******************************************************************/

#include <pci.h>
#define NDEBUG
#include <debug.h>

/* GLOBALS ********************************************************************/

/* FUNCTIONS ******************************************************************/

ULONG
NTAPI
PciBridgeIoBase(IN PPCI_COMMON_HEADER PciData)
{
    BOOLEAN Is32Bit;
    ULONG Base, IoBase;
    ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE);

    /* Get the base */
    Base = PciData->u.type1.IOLimit;

    /* Low bit specifies 32-bit address, top bits specify the base */
    Is32Bit = (Base & 0xF) == 1;
    IoBase = (Base & 0xF0) << 8;

    /* Is it 32-bit? */
    if (Is32Bit)
    {
        /* Read the upper 16-bits from the other register */
        IoBase |= PciData->u.type1.IOBaseUpper16 << 16;
        ASSERT(PciData->u.type1.IOLimit & 0x1);
    }

    /* Return the base address */
    return IoBase;
}

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;
}

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);
}

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;
}

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;
}

PHYSICAL_ADDRESS
NTAPI
PciBridgePrefetchMemoryLimit(IN PPCI_COMMON_HEADER PciData)
{
    BOOLEAN Is64Bit;
    LARGE_INTEGER Limit;
    USHORT PrefetchLimit;
    ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE);

    /* Get the base */
    PrefetchLimit = PciData->u.type1.PrefetchLimit;

    /* Low bit specifies 64-bit address, top bits specify the limit */
    Is64Bit = (PrefetchLimit & 0xF) == 1;
    Limit.LowPart = (PrefetchLimit << 16) | 0xFFFFF;

    /* Is it 64-bit? */
    if (Is64Bit)
    {
        /* Read the upper 32-bits from the other register */
        Limit.HighPart = PciData->u.type1.PrefetchLimitUpper32;
    }

    /* Return the limit */
    return Limit;
}

ULONG
NTAPI
PciBridgeMemoryWorstCaseAlignment(IN ULONG Length)
{
    ULONG Alignment;
    ASSERT(Length != 0);

    /* Start with highest alignment (2^31) */
    Alignment = 0x80000000;

    /* Keep dividing until we reach the correct power of two */
    while (!(Length & Alignment)) Alignment >>= 1;

    /* Return the alignment */
    return Alignment;
}

BOOLEAN
NTAPI
PciBridgeIsPositiveDecode(IN PPCI_PDO_EXTENSION PdoExtension)
{
    /* Undocumented ACPI Method PDEC to get positive decode settings */
    return PciIsSlotPresentInParentMethod(PdoExtension, 'CEDP');
}

BOOLEAN
NTAPI
PciBridgeIsSubtractiveDecode(IN PPCI_CONFIGURATOR_CONTEXT Context)
{
    PPCI_COMMON_HEADER Current, PciData;
    PPCI_PDO_EXTENSION PdoExtension;

    /* Get pointers from context */
    Current = Context->Current;
    PciData = Context->PciData;
    PdoExtension = Context->PdoExtension;

    /* Only valid for PCI-to-PCI bridges */
    ASSERT((Current->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
           (Current->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI));

    /* Check for hacks first, then check the ProgIf of the bridge */
    if (!(PdoExtension->HackFlags & PCI_HACK_SUBTRACTIVE_DECODE) &&
         (Current->ProgIf != 1) &&
         ((PciData->u.type1.IOLimit & 0xF0) == 0xF0))
    {
        /* A subtractive decode bridge would have a ProgIf 1, and no I/O limit */
        DPRINT("Subtractive decode does not seem to be enabled\n");
        return FALSE;
    }

    /*
     * Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
     * i820, i840, i845 Chipsets) that have subtractive decode broken.
     */
    if (((PdoExtension->VendorId == 0x8086) &&
         ((PdoExtension->DeviceId == 0x2418) ||
          (PdoExtension->DeviceId == 0x2428) ||
          (PdoExtension->DeviceId == 0x244E) ||
          (PdoExtension->DeviceId == 0x2448))) ||
        (PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE))
    {
        /* Check if the ACPI BIOS says positive decode should be enabled */
        if (PciBridgeIsPositiveDecode(PdoExtension))
        {
            /* Obey ACPI */
            DPRINT1("Putting bridge in positive decode because of PDEC\n");
            return FALSE;
        }
    }

    /* If we found subtractive decode, we'll need a resource update later */
    DPRINT1("PCI : Subtractive decode on 0x%x\n", Current->u.type1.SecondaryBus);
    PdoExtension->UpdateHardware = TRUE;
    return TRUE;
}

VOID
NTAPI
PPBridge_SaveCurrentSettings(IN PPCI_CONFIGURATOR_CONTEXT Context)
{
    NTSTATUS Status;
    PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor;
    PIO_RESOURCE_DESCRIPTOR IoDescriptor;
    PPCI_FUNCTION_RESOURCES Resources;
    PCI_COMMON_HEADER BiosData;
    PPCI_COMMON_HEADER Current;
    PPCI_COMMON_CONFIG SavedConfig;
    ULONG i, Bar, BarMask;
    PULONG BarArray;
    PHYSICAL_ADDRESS Limit, Base, Length;
    BOOLEAN HaveIoLimit, CheckAlignment;
    PPCI_PDO_EXTENSION PdoExtension;

    /* Get the pointers from the extension */
    PdoExtension = Context->PdoExtension;
    Resources = PdoExtension->Resources;
    Current = Context->Current;

    /* Check if decodes are disabled */
    if (!(Context->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE)))
    {
        /* Well, we're going to need them from somewhere, use the registry data */
        Status = PciGetBiosConfig(PdoExtension, &BiosData);
        if (NT_SUCCESS(Status)) Current = &BiosData;
    }

    /* Scan all current and limit descriptors for each BAR needed */
    BarArray = Current->u.type1.BaseAddresses;
    for (i = 0; i < 6; i++)
    {
        /* Get the current resource descriptor, and the limit requirement */
        CmDescriptor = &Resources->Current[i];
        IoDescriptor = &Resources->Limit[i];

        /* Copy descriptor data, skipping null descriptors */
        CmDescriptor->Type = IoDescriptor->Type;
        if (CmDescriptor->Type == CmResourceTypeNull) continue;
        CmDescriptor->Flags = IoDescriptor->Flags;
        CmDescriptor->ShareDisposition = IoDescriptor->ShareDisposition;

        /* Initialize the high-parts to zero, since most stuff is 32-bit only */
        Base.QuadPart = Limit.QuadPart = Length.QuadPart = 0;

        /* Check if we're handling PCI BARs, or the ROM BAR */
        if ((i < PCI_TYPE1_ADDRESSES) || (i == 5))
        {
            /* Is this the ROM BAR? */
            if (i == 5)
            {
                /* Read the correct bar, with the appropriate mask */
                Bar = Current->u.type1.ROMBaseAddress;
                BarMask = PCI_ADDRESS_ROM_ADDRESS_MASK;

                /* Decode the base address, and write down the length */
                Base.LowPart = Bar & BarMask;
                DPRINT1("ROM BAR Base: %lx\n", Base.LowPart);
                CmDescriptor->u.Memory.Length = IoDescriptor->u.Memory.Length;
            }
            else
            {
                /* Otherwise, get the BAR from the array */
                Bar = BarArray[i];

                /* Is this an I/O BAR? */
                if (Bar & PCI_ADDRESS_IO_SPACE)
                {
                    /* Set the correct mask */
                    ASSERT(CmDescriptor->Type == CmResourceTypePort);
                    BarMask = PCI_ADDRESS_IO_ADDRESS_MASK;
                }
                else
                {
                    /* This is a memory BAR, set the correct base */
                    ASSERT(CmDescriptor->Type == CmResourceTypeMemory);
                    BarMask = PCI_ADDRESS_MEMORY_ADDRESS_MASK;

                    /* IS this a 64-bit BAR? */
                    if ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)
                    {
                        /* Read the next 32-bits as well, ie, the next BAR */
                        Base.HighPart = BarArray[i + 1];
                    }
                }

                /* Decode the base address, and write down the length */
                Base.LowPart = Bar & BarMask;
                DPRINT1("BAR Base: %lx\n", Base.LowPart);
                CmDescriptor->u.Generic.Length = IoDescriptor->u.Generic.Length;
            }
        }
        else
        {
            /* Reset loop conditions */
            HaveIoLimit = FALSE;
            CheckAlignment = FALSE;

            /* Check which descriptor is being parsed */
            if (i == 2)
            {
                /* I/O Port Requirements */
                Base.LowPart = PciBridgeIoBase(Current);
                Limit.LowPart = PciBridgeIoLimit(Current);
                DPRINT1("Bridge I/O Base and Limit: %lx %lx\n",
                         Base.LowPart, Limit.LowPart);

                /* Do we have any I/O Port data? */
                if (!(Base.LowPart) && (Current->u.type1.IOLimit))
                {
                    /* There's a limit */
                    HaveIoLimit = TRUE;
                }
            }
            else if (i == 3)
            {
                /* Memory requirements */
                Base.LowPart = PciBridgeMemoryBase(Current);
                Limit.LowPart = PciBridgeMemoryLimit(Current);

                /* These should always be there, so check their alignment */
                DPRINT1("Bridge MEM Base and Limit: %lx %lx\n",
                         Base.LowPart, Limit.LowPart);
                CheckAlignment = TRUE;
            }
            else if (i == 4)
            {
                /* This should only be present for prefetch memory */
                ASSERT(CmDescriptor->Flags & CM_RESOURCE_MEMORY_PREFETCHABLE);
                Base = PciBridgePrefetchMemoryBase(Current);
                Limit = PciBridgePrefetchMemoryLimit(Current);

                /* If it's there, check the alignment */
                DPRINT1("Bridge Prefetch MEM Base and Limit: %I64x %I64x\n", Base, Limit);
                CheckAlignment = TRUE;
            }

            /* Check for invalid base address */
            if (Base.QuadPart >= Limit.QuadPart)
            {
                /* Assume the descriptor is bogus */
                CmDescriptor->Type = CmResourceTypeNull;
                IoDescriptor->Type = CmResourceTypeNull;
                continue;
            }

            /* Check if there's no memory, and no I/O port either */
            if (!(Base.LowPart) && !(HaveIoLimit))
            {
                /* This seems like a bogus requirement, ignore it */
                CmDescriptor->Type = CmResourceTypeNull;
                continue;
            }

            /* Set the length to be the limit - the base; should always be 32-bit */
            Length.QuadPart = Limit.LowPart - Base.LowPart + 1;
            ASSERT(Length.HighPart == 0);
            CmDescriptor->u.Generic.Length = Length.LowPart;

            /* Check if alignment should be set */
            if (CheckAlignment)
            {
                /* Compute the required alignment for this length */
                ASSERT(CmDescriptor->u.Memory.Length > 0);
                IoDescriptor->u.Memory.Alignment =
                    PciBridgeMemoryWorstCaseAlignment(CmDescriptor->u.Memory.Length);
            }
        }

        /* Now set the base address */
        CmDescriptor->u.Generic.Start.LowPart = Base.LowPart;
    }

    /* Save PCI settings into the PDO extension for easy access later */
    PdoExtension->Dependent.type1.PrimaryBus = Current->u.type1.PrimaryBus;
    PdoExtension->Dependent.type1.SecondaryBus = Current->u.type1.SecondaryBus;
    PdoExtension->Dependent.type1.SubordinateBus = Current->u.type1.SubordinateBus;

    /* Check for subtractive decode bridges */
    if (PdoExtension->Dependent.type1.SubtractiveDecode)
    {
        /* Check if legacy VGA decodes are enabled */
        DPRINT1("Subtractive decode bridge\n");
        if (Current->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA)
        {
            /* Save this setting for later */
            DPRINT1("VGA Bridge\n");
            PdoExtension->Dependent.type1.VgaBitSet = TRUE;
        }

        /* Legacy ISA decoding is not compatible with subtractive decode */
        ASSERT(PdoExtension->Dependent.type1.IsaBitSet == FALSE);
    }
    else
    {
        /* Check if legacy VGA decodes are enabled */
        if (Current->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA)
        {
            /* Save this setting for later */
            DPRINT1("VGA Bridge\n");
            PdoExtension->Dependent.type1.VgaBitSet = TRUE;

            /* And on positive decode, we'll also need extra resources locked */
            PdoExtension->AdditionalResourceCount = 4;
        }

        /* Check if legacy ISA decoding is enabled */
        if (Current->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_ISA)
        {
            /* Save this setting for later */
            DPRINT1("ISA Bridge\n");
            PdoExtension->Dependent.type1.IsaBitSet = TRUE;
        }
    }

    /*
     * Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
     * i820, i840, i845 Chipsets) that have subtractive decode broken.
     */
    if (((PdoExtension->VendorId == 0x8086) &&
         ((PdoExtension->DeviceId == 0x2418) ||
          (PdoExtension->DeviceId == 0x2428) ||
          (PdoExtension->DeviceId == 0x244E) ||
          (PdoExtension->DeviceId == 0x2448))) ||
        (PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE))
    {
        /* Check if subtractive decode is actually enabled */
        if (PdoExtension->Dependent.type1.SubtractiveDecode)
        {
            /* We're going to need a copy of the configuration for later use */
            DPRINT1("apply config save hack to ICH subtractive decode\n");
            SavedConfig = ExAllocatePoolWithTag(0, PCI_COMMON_HDR_LENGTH, 'PciP');
            PdoExtension->ParentFdoExtension->PreservedConfig = SavedConfig;
            if (SavedConfig) RtlCopyMemory(SavedConfig, Current, PCI_COMMON_HDR_LENGTH);
        }
    }
}

VOID
NTAPI
PPBridge_SaveLimits(IN PPCI_CONFIGURATOR_CONTEXT Context)
{
    PIO_RESOURCE_DESCRIPTOR Limit;
    PULONG BarArray;
    PHYSICAL_ADDRESS MemoryLimit;
    ULONG i;
    PPCI_COMMON_HEADER Working;
    PPCI_PDO_EXTENSION PdoExtension;

    /* Get the pointers from the context */
    Working = Context->PciData;
    PdoExtension = Context->PdoExtension;

    /* Scan the BARs into the limit descriptors */
    BarArray = Working->u.type1.BaseAddresses;
    Limit = PdoExtension->Resources->Limit;

    /* First of all, loop all the BARs */
    for (i = 0; i < PCI_TYPE1_ADDRESSES; i++)
    {
        /* Create a descriptor for their limits */
        if (PciCreateIoDescriptorFromBarLimit(&Limit[i], &BarArray[i], FALSE))
        {
            /* This was a 64-bit descriptor, make sure there's space */
            ASSERT((i + 1) < PCI_TYPE1_ADDRESSES);

            /* Skip the next descriptor since this one is double sized */
            i++;
            Limit[i].Type = CmResourceTypeNull;
        }
    }

    /* Check if this is a subtractive decode bridge */
    if (PciBridgeIsSubtractiveDecode(Context))
    {
        /* This bridge is subtractive */
        PdoExtension->Dependent.type1.SubtractiveDecode = TRUE;

        /* Subtractive bridges cannot use legacy ISA or VGA functionality */
        PdoExtension->Dependent.type1.IsaBitSet = FALSE;
        PdoExtension->Dependent.type1.VgaBitSet = FALSE;
    }

    /* For normal decode bridges, we'll need to find the bridge limits too */
    if (!PdoExtension->Dependent.type1.SubtractiveDecode)
    {
        /* Loop the descriptors that are left, to store the bridge limits */
        for (i = PCI_TYPE1_ADDRESSES; i < 5; i++)
        {
            /* No 64-bit memory addresses, and set the address to 0 to begin */
            MemoryLimit.HighPart = 0;
            (&Limit[i])->u.Port.MinimumAddress.QuadPart = 0;

            /* Are we getting the I/O limit? */
            if (i == 2)
            {
                /* There should be one, get it */
                ASSERT(Working->u.type1.IOLimit != 0);
                ASSERT((Working->u.type1.IOLimit & 0x0E) == 0);
                MemoryLimit.LowPart = PciBridgeIoLimit(Working);

                /* Build a descriptor for this limit */
                (&Limit[i])->Type = CmResourceTypePort;
                (&Limit[i])->Flags = CM_RESOURCE_PORT_WINDOW_DECODE |
                                     CM_RESOURCE_PORT_POSITIVE_DECODE;
                (&Limit[i])->u.Port.Alignment = 0x1000;
                (&Limit[i])->u.Port.MinimumAddress.QuadPart = 0;
                (&Limit[i])->u.Port.MaximumAddress = MemoryLimit;
                (&Limit[i])->u.Port.Length = 0;
            }
            else if (i == 3)
            {
                /* There should be a valid memory limit, get it */
                ASSERT((Working->u.type1.MemoryLimit & 0xF) == 0);
                MemoryLimit.LowPart = PciBridgeMemoryLimit(Working);

                /* Build the descriptor for it */
                (&Limit[i])->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
                (&Limit[i])->Type = CmResourceTypeMemory;
                (&Limit[i])->u.Memory.Alignment = 0x100000;
                (&Limit[i])->u.Memory.MinimumAddress.QuadPart = 0;
                (&Limit[i])->u.Memory.MaximumAddress = MemoryLimit;
                (&Limit[i])->u.Memory.Length = 0;
            }
            else if (Working->u.type1.PrefetchLimit)
            {
                /* Get the prefetch memory limit, if there is one */
                MemoryLimit = PciBridgePrefetchMemoryLimit(Working);

                /* Write out the descriptor for it */
                (&Limit[i])->Flags = CM_RESOURCE_MEMORY_PREFETCHABLE;
                (&Limit[i])->Type = CmResourceTypeMemory;
                (&Limit[i])->u.Memory.Alignment = 0x100000;
                (&Limit[i])->u.Memory.MinimumAddress.QuadPart = 0;
                (&Limit[i])->u.Memory.MaximumAddress = MemoryLimit;
                (&Limit[i])->u.Memory.Length = 0;
            }
            else
            {
                /* Blank descriptor */
                (&Limit[i])->Type = CmResourceTypeNull;
            }
        }
    }

    /* Does the ROM have its own BAR? */
    if (Working->u.type1.ROMBaseAddress & PCI_ROMADDRESS_ENABLED)
    {
        /* Build a limit for it as well */
        PciCreateIoDescriptorFromBarLimit(&Limit[i],
                                          &Working->u.type1.ROMBaseAddress,
                                          TRUE);
    }
}

VOID
NTAPI
PPBridge_MassageHeaderForLimitsDetermination(IN PPCI_CONFIGURATOR_CONTEXT Context)
{
    PPCI_COMMON_HEADER PciData, Current;

    /* Get pointers from context */
    PciData = Context->PciData;
    Current = Context->Current;

    /*
     * Write FFh everywhere so that the PCI bridge ignores what it can't handle.
     * Based on the bits that were ignored (still 0), this is how we can tell
     * what the limit is.
     */
    RtlFillMemory(PciData->u.type1.BaseAddresses,
                  FIELD_OFFSET(PCI_COMMON_HEADER, u.type1.CapabilitiesPtr) -
                  FIELD_OFFSET(PCI_COMMON_HEADER, u.type1.BaseAddresses),
                  0xFF);

    /* Copy the saved settings from the current context into the PCI header */
    PciData->u.type1.PrimaryBus = Current->u.type1.PrimaryBus;
    PciData->u.type1.SecondaryBus = Current->u.type1.SecondaryBus;
    PciData->u.type1.SubordinateBus = Current->u.type1.SubordinateBus;
    PciData->u.type1.SecondaryLatency = Current->u.type1.SecondaryLatency;

    /* No I/O limit or base. The bottom base bit specifies that FIXME */
    PciData->u.type1.IOBaseUpper16 = 0xFFFE;
    PciData->u.type1.IOLimitUpper16 = 0xFFFF;

    /* Save secondary status before it gets cleared */
    Context->SecondaryStatus = Current->u.type1.SecondaryStatus;

    /* Clear secondary status */
    Current->u.type1.SecondaryStatus = 0;
    PciData->u.type1.SecondaryStatus = 0;
}

VOID
NTAPI
PPBridge_RestoreCurrent(IN PPCI_CONFIGURATOR_CONTEXT Context)
{
    /* Copy back the secondary status register */
    Context->Current->u.type1.SecondaryStatus = Context->SecondaryStatus;
}

VOID
NTAPI
PPBridge_GetAdditionalResourceDescriptors(IN PPCI_CONFIGURATOR_CONTEXT Context,
                                          IN PPCI_COMMON_HEADER PciData,
                                          IN PIO_RESOURCE_DESCRIPTOR IoDescriptor)
{

    UNREFERENCED_PARAMETER(Context);

    /* Does this bridge have VGA decodes on it? */
    if (PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA)
    {
        /* Build a private descriptor with 3 entries */
        IoDescriptor->Type = CmResourceTypeDevicePrivate;
        IoDescriptor->u.DevicePrivate.Data[0] = 3;
        IoDescriptor->u.DevicePrivate.Data[1] = 3;

        /* First, the VGA range at 0xA0000 */
        IoDescriptor[1].Type = CmResourceTypeMemory;
        IoDescriptor[1].Flags = CM_RESOURCE_MEMORY_READ_WRITE;
        IoDescriptor[1].u.Port.Length = 0x20000;
        IoDescriptor[1].u.Port.Alignment = 1;
        IoDescriptor[1].u.Port.MinimumAddress.QuadPart = 0xA0000;
        IoDescriptor[1].u.Port.MaximumAddress.QuadPart = 0xBFFFF;

        /* Then, the VGA registers at 0x3B0 */
        IoDescriptor[2].Type = CmResourceTypePort;
        IoDescriptor[2].Flags = CM_RESOURCE_PORT_POSITIVE_DECODE |
                                CM_RESOURCE_PORT_10_BIT_DECODE;
        IoDescriptor[2].u.Port.Length = 12;
        IoDescriptor[2].u.Port.Alignment = 1;
        IoDescriptor[2].u.Port.MinimumAddress.QuadPart = 0x3B0;
        IoDescriptor[2].u.Port.MaximumAddress.QuadPart = 0x3BB;

        /* And finally the VGA registers at 0x3C0 */
        IoDescriptor[3].Type = CmResourceTypePort;
        IoDescriptor[3].Flags = CM_RESOURCE_PORT_POSITIVE_DECODE |
                                CM_RESOURCE_PORT_10_BIT_DECODE;
        IoDescriptor[3].u.Port.Length = 32;
        IoDescriptor[3].u.Port.Alignment = 1;
        IoDescriptor[3].u.Port.MinimumAddress.QuadPart = 0x3C0;
        IoDescriptor[3].u.Port.MaximumAddress.QuadPart = 0x3DF;
    }
}

VOID
NTAPI
PPBridge_ResetDevice(IN PPCI_PDO_EXTENSION PdoExtension,
                     IN PPCI_COMMON_HEADER PciData)
{
    UNREFERENCED_PARAMETER(PdoExtension);
    UNREFERENCED_PARAMETER(PciData);
    UNIMPLEMENTED_DBGBREAK();
}

VOID
NTAPI
PPBridge_ChangeResourceSettings(IN PPCI_PDO_EXTENSION PdoExtension,
                                IN PPCI_COMMON_HEADER PciData)
{
    //BOOLEAN IoActive;
    PPCI_FDO_EXTENSION FdoExtension;
    PPCI_FUNCTION_RESOURCES PciResources;
    ULONG i;

    /* Check if I/O Decodes are enabled */
    //IoActive = (PciData->u.type1.IOBase & 0xF) == 1;

    /*
     * Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
     * i820, i840, i845 Chipsets) that don't have subtractive decode broken.
     * If they do have broken subtractive support, or if they are not ICH bridges,
     * then check if the bridge supports substractive decode at all.
     */
    if ((((PdoExtension->VendorId == 0x8086) &&
         ((PdoExtension->DeviceId == 0x2418) ||
          (PdoExtension->DeviceId == 0x2428) ||
          (PdoExtension->DeviceId == 0x244E) ||
          (PdoExtension->DeviceId == 0x2448))) &&
         (!(PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE) ||
         (PdoExtension->Dependent.type1.SubtractiveDecode == FALSE))) ||
        (PdoExtension->Dependent.type1.SubtractiveDecode == FALSE))
    {
        /* No resources are needed on a subtractive decode bridge */
        PciData->u.type1.MemoryBase = 0xFFFF;
        PciData->u.type1.PrefetchBase = 0xFFFF;
        PciData->u.type1.IOBase = 0xFF;
        PciData->u.type1.IOLimit = 0;
        PciData->u.type1.MemoryLimit = 0;
        PciData->u.type1.PrefetchLimit = 0;
        PciData->u.type1.PrefetchBaseUpper32 = 0;
        PciData->u.type1.PrefetchLimitUpper32 = 0;
        PciData->u.type1.IOBaseUpper16 = 0;
        PciData->u.type1.IOLimitUpper16 = 0;
    }
    else
    {
        /*
         * Otherwise, get the FDO to read the old PCI configuration header that
         * had been saved by the hack in PPBridge_SaveCurrentSettings.
         */
        FdoExtension = PdoExtension->ParentFdoExtension;
        ASSERT(PdoExtension->Resources == NULL);

        /* Read the PCI header data and use that here */
        PciData->u.type1.IOBase = FdoExtension->PreservedConfig->u.type1.IOBase;
        PciData->u.type1.IOLimit = FdoExtension->PreservedConfig->u.type1.IOLimit;
        PciData->u.type1.MemoryBase = FdoExtension->PreservedConfig->u.type1.MemoryBase;
        PciData->u.type1.MemoryLimit = FdoExtension->PreservedConfig->u.type1.MemoryLimit;
        PciData->u.type1.PrefetchBase = FdoExtension->PreservedConfig->u.type1.PrefetchBase;
        PciData->u.type1.PrefetchLimit = FdoExtension->PreservedConfig->u.type1.PrefetchLimit;
        PciData->u.type1.PrefetchBaseUpper32 = FdoExtension->PreservedConfig->u.type1.PrefetchBaseUpper32;
        PciData->u.type1.PrefetchLimitUpper32 = FdoExtension->PreservedConfig->u.type1.PrefetchLimitUpper32;
        PciData->u.type1.IOBaseUpper16 = FdoExtension->PreservedConfig->u.type1.IOBaseUpper16;
        PciData->u.type1.IOLimitUpper16 = FdoExtension->PreservedConfig->u.type1.IOLimitUpper16;
    }

    /* Loop bus resources */
    PciResources = PdoExtension->Resources;
    if (PciResources)
    {
        /* Loop each resource type (the BARs, ROM BAR and Prefetch) */
        for (i = 0; i < 6; i++)
        {
            UNIMPLEMENTED;
        }
    }

    /* Copy the bus number data */
    PciData->u.type1.PrimaryBus = PdoExtension->Dependent.type1.PrimaryBus;
    PciData->u.type1.SecondaryBus = PdoExtension->Dependent.type1.SecondaryBus;
    PciData->u.type1.SubordinateBus = PdoExtension->Dependent.type1.SubordinateBus;

    /* Copy the decode flags */
    if (PdoExtension->Dependent.type1.IsaBitSet)
    {
        PciData->u.type1.BridgeControl |= PCI_ENABLE_BRIDGE_ISA;
    }

    if (PdoExtension->Dependent.type1.VgaBitSet)
    {
        PciData->u.type1.BridgeControl |= PCI_ENABLE_BRIDGE_VGA;
    }
}

/* EOF */
