reactos/drivers/bus/pcix/device.c

293 lines
9.6 KiB
C

/*
* PROJECT: ReactOS PCI Bus Driver
* LICENSE: BSD - See COPYING.ARM in the top level directory
* FILE: drivers/bus/pci/device.c
* PURPOSE: Device Management
* PROGRAMMERS: ReactOS Portable Systems Group
*/
/* INCLUDES *******************************************************************/
#include <pci.h>
#define NDEBUG
#include <debug.h>
/* FUNCTIONS ******************************************************************/
VOID
NTAPI
Device_SaveCurrentSettings(IN PPCI_CONFIGURATOR_CONTEXT Context)
{
PPCI_COMMON_HEADER PciData;
PIO_RESOURCE_DESCRIPTOR IoDescriptor;
PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor;
PPCI_FUNCTION_RESOURCES Resources;
PULONG BarArray;
ULONG Bar, BarMask, i;
/* Get variables from context */
PciData = Context->Current;
Resources = Context->PdoExtension->Resources;
/* Loop all the PCI BARs */
BarArray = PciData->u.type0.BaseAddresses;
for (i = 0; i <= PCI_TYPE0_ADDRESSES; i++)
{
/* Get the resource descriptor and limit descriptor for this BAR */
CmDescriptor = &Resources->Current[i];
IoDescriptor = &Resources->Limit[i];
/* Build the resource descriptor based on the limit descriptor */
CmDescriptor->Type = IoDescriptor->Type;
if (CmDescriptor->Type == CmResourceTypeNull) continue;
CmDescriptor->Flags = IoDescriptor->Flags;
CmDescriptor->ShareDisposition = IoDescriptor->ShareDisposition;
CmDescriptor->u.Generic.Start.HighPart = 0;
CmDescriptor->u.Generic.Length = IoDescriptor->u.Generic.Length;
/* Check if we're handling PCI BARs, or the ROM BAR */
if (i < PCI_TYPE0_ADDRESSES)
{
/* Read the actual BAR value */
Bar = BarArray[i];
/* Check if this is an I/O BAR */
if (Bar & PCI_ADDRESS_IO_SPACE)
{
/* Use the right mask to get the I/O port base address */
ASSERT(CmDescriptor->Type == CmResourceTypePort);
BarMask = PCI_ADDRESS_IO_ADDRESS_MASK;
}
else
{
/* It's a RAM BAR, use the right mask to get the base address */
ASSERT(CmDescriptor->Type == CmResourceTypeMemory);
BarMask = PCI_ADDRESS_MEMORY_ADDRESS_MASK;
/* Check if it's a 64-bit BAR */
if ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)
{
/* The next BAR value is actually the high 32-bits */
CmDescriptor->u.Memory.Start.HighPart = BarArray[i + 1];
}
else if ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_20BIT)
{
/* Legacy BAR, don't read more than 20 bits of the address */
BarMask = 0xFFFF0;
}
}
}
else
{
/* Actually a ROM BAR, so read the correct register */
Bar = PciData->u.type0.ROMBaseAddress;
/* Apply the correct mask for ROM BARs */
BarMask = PCI_ADDRESS_ROM_ADDRESS_MASK;
/* Make sure it's enabled */
if (!(Bar & PCI_ROMADDRESS_ENABLED))
{
/* If it isn't, then a descriptor won't be built for it */
CmDescriptor->Type = CmResourceTypeNull;
continue;
}
}
/* Now we have the right mask, read the actual address from the BAR */
Bar &= BarMask;
CmDescriptor->u.Memory.Start.LowPart = Bar;
/* And check for invalid BAR addresses */
if (!(CmDescriptor->u.Memory.Start.HighPart | Bar))
{
/* Skip these descriptors */
CmDescriptor->Type = CmResourceTypeNull;
DPRINT1("Invalid BAR\n");
}
}
/* Also save the sub-IDs that came directly from the PCI header */
Context->PdoExtension->SubsystemVendorId = PciData->u.type0.SubVendorID;
Context->PdoExtension->SubsystemId = PciData->u.type0.SubSystemID;
}
VOID
NTAPI
Device_SaveLimits(IN PPCI_CONFIGURATOR_CONTEXT Context)
{
PPCI_COMMON_HEADER Current, PciData;
PPCI_PDO_EXTENSION PdoExtension;
PULONG BarArray;
PIO_RESOURCE_DESCRIPTOR Limit;
ULONG i;
/* Get pointers from the context */
PdoExtension = Context->PdoExtension;
Current = Context->Current;
PciData = Context->PciData;
/* And get the array of bARs */
BarArray = PciData->u.type0.BaseAddresses;
/* First, check for IDE controllers that are not in native mode */
if ((PdoExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
(PdoExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR) &&
(PdoExtension->ProgIf & 5) != 5)
{
/* They should not be using any non-legacy resources */
BarArray[0] = 0;
BarArray[1] = 0;
BarArray[2] = 0;
BarArray[3] = 0;
}
else if ((PdoExtension->VendorId == 0x5333) &&
((PdoExtension->DeviceId == 0x88F0) ||
(PdoExtension->DeviceId == 0x8880)))
{
/*
* The problem is caused by the S3 Vision 968/868 video controller which
* is used on the Diamond Stealth 64 Video 3000 series, Number Nine 9FX
* motion 771, and other popular video cards, all containing a memory bug.
* The 968/868 claims to require 32 MB of memory, but it actually decodes
* 64 MB of memory.
*/
for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
{
/* Find its 32MB RAM BAR */
if (BarArray[i] == 0xFE000000)
{
/* Increase it to 64MB to make sure nobody touches the buffer */
BarArray[i] = 0xFC000000;
DPRINT1("PCI - Adjusted broken S3 requirement from 32MB to 64MB\n");
}
}
}
/* Check for Cirrus Logic GD5430/5440 cards */
if ((PdoExtension->VendorId == 0x1013) && (PdoExtension->DeviceId == 0xA0))
{
/* Check for the I/O port requirement */
if (BarArray[1] == 0xFC01)
{
/* Check for completely bogus BAR */
if (Current->u.type0.BaseAddresses[1] == 1)
{
/* Ignore it */
BarArray[1] = 0;
DPRINT1("PCI - Ignored Cirrus GD54xx broken IO requirement (400 ports)\n");
}
else
{
/* Otherwise, this BAR seems okay */
DPRINT1("PCI - Cirrus GD54xx 400 port IO requirement has a valid setting (%08x)\n",
Current->u.type0.BaseAddresses[1]);
}
}
else if (BarArray[1])
{
/* Strange, the I/O BAR was not found as expected (or at all) */
DPRINT1("PCI - Warning Cirrus Adapter 101300a0 has unexpected resource requirement (%08x)\n",
BarArray[1]);
}
}
/* Finally, process all the limit descriptors */
Limit = PdoExtension->Resources->Limit;
for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
{
/* And build them based on the BARs */
if (PciCreateIoDescriptorFromBarLimit(&Limit[i], &BarArray[i], FALSE))
{
/* This function returns TRUE if the BAR was 64-bit, handle this */
ASSERT((i + 1) < PCI_TYPE0_ADDRESSES);
i++;
Limit[i].Type = CmResourceTypeNull;
}
}
/* Create the last descriptor based on the ROM address */
PciCreateIoDescriptorFromBarLimit(&Limit[i],
&PciData->u.type0.ROMBaseAddress,
TRUE);
}
VOID
NTAPI
Device_MassageHeaderForLimitsDetermination(IN PPCI_CONFIGURATOR_CONTEXT Context)
{
PPCI_COMMON_HEADER PciData;
PPCI_PDO_EXTENSION PdoExtension;
PULONG BarArray;
ULONG i = 0;
/* Get pointers from context data */
PdoExtension = Context->PdoExtension;
PciData = Context->PciData;
/* Get the array of BARs */
BarArray = PciData->u.type0.BaseAddresses;
/* Check for IDE controllers that are not in native mode */
if ((PdoExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
(PdoExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR) &&
(PdoExtension->ProgIf & 5) != 5)
{
/* These controllers only use legacy resources */
i = 4;
}
/* Set all the bits on, which will allow us to recover the limit data */
for (i = 0; i < PCI_TYPE0_ADDRESSES; i++) BarArray[i] = 0xFFFFFFFF;
/* Do the same for the PCI ROM BAR */
PciData->u.type0.ROMBaseAddress = PCI_ADDRESS_ROM_ADDRESS_MASK;
}
VOID
NTAPI
Device_RestoreCurrent(IN PPCI_CONFIGURATOR_CONTEXT Context)
{
UNREFERENCED_PARAMETER(Context);
/* Nothing to do for devices */
return;
}
VOID
NTAPI
Device_GetAdditionalResourceDescriptors(IN PPCI_CONFIGURATOR_CONTEXT Context,
IN PPCI_COMMON_HEADER PciData,
IN PIO_RESOURCE_DESCRIPTOR IoDescriptor)
{
UNREFERENCED_PARAMETER(Context);
UNREFERENCED_PARAMETER(PciData);
UNREFERENCED_PARAMETER(IoDescriptor);
/* Not yet implemented */
UNIMPLEMENTED_DBGBREAK();
}
VOID
NTAPI
Device_ResetDevice(IN PPCI_PDO_EXTENSION PdoExtension,
IN PPCI_COMMON_HEADER PciData)
{
UNREFERENCED_PARAMETER(PdoExtension);
UNREFERENCED_PARAMETER(PciData);
/* Not yet implemented */
UNIMPLEMENTED_DBGBREAK();
}
VOID
NTAPI
Device_ChangeResourceSettings(IN PPCI_PDO_EXTENSION PdoExtension,
IN PPCI_COMMON_HEADER PciData)
{
UNREFERENCED_PARAMETER(PdoExtension);
UNREFERENCED_PARAMETER(PciData);
/* Not yet implemented */
UNIMPLEMENTED_DBGBREAK();
}
/* EOF */