📄 pci.c
字号:
/*
* PROJECT: ReactOS HAL
* LICENSE: GPL - See COPYING in the top level directory
* FILE: hal/halx86/generic/pci.c
* PURPOSE: PCI Bus Support (Configuration Space, Resource Allocation)
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <hal.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
BOOLEAN HalpPCIConfigInitialized;
ULONG HalpMinPciBus, HalpMaxPciBus;
KSPIN_LOCK HalpPCIConfigLock;
PCI_CONFIG_HANDLER PCIConfigHandler;
/* PCI Operation Matrix */
UCHAR PCIDeref[4][4] =
{
{0, 1, 2, 2}, // ULONG-aligned offset
{1, 1, 1, 1}, // UCHAR-aligned offset
{2, 1, 2, 2}, // USHORT-aligned offset
{1, 1, 1, 1} // UCHAR-aligned offset
};
/* Type 1 PCI Bus */
PCI_CONFIG_HANDLER PCIConfigHandlerType1 =
{
/* Synchronization */
(FncSync)HalpPCISynchronizeType1,
(FncReleaseSync)HalpPCIReleaseSynchronzationType1,
/* Read */
{
(FncConfigIO)HalpPCIReadUlongType1,
(FncConfigIO)HalpPCIReadUcharType1,
(FncConfigIO)HalpPCIReadUshortType1
},
/* Write */
{
(FncConfigIO)HalpPCIWriteUlongType1,
(FncConfigIO)HalpPCIWriteUcharType1,
(FncConfigIO)HalpPCIWriteUshortType1
}
};
/* Type 2 PCI Bus */
PCI_CONFIG_HANDLER PCIConfigHandlerType2 =
{
/* Synchronization */
(FncSync)HalpPCISynchronizeType2,
(FncReleaseSync)HalpPCIReleaseSynchronzationType2,
/* Read */
{
(FncConfigIO)HalpPCIReadUlongType2,
(FncConfigIO)HalpPCIReadUcharType2,
(FncConfigIO)HalpPCIReadUshortType2
},
/* Write */
{
(FncConfigIO)HalpPCIWriteUlongType2,
(FncConfigIO)HalpPCIWriteUcharType2,
(FncConfigIO)HalpPCIWriteUshortType2
}
};
PCIPBUSDATA HalpFakePciBusData =
{
{
PCI_DATA_TAG,
PCI_DATA_VERSION,
HalpReadPCIConfig,
HalpWritePCIConfig,
NULL,
NULL,
{{{0}}},
{0, 0, 0, 0}
},
{{0}},
32,
};
BUS_HANDLER HalpFakePciBusHandler =
{
1,
PCIBus,
PCIConfiguration,
0,
NULL,
NULL,
&HalpFakePciBusData,
0,
{0, 0, 0, 0},
HalpGetPCIData,
HalpSetPCIData,
NULL,
HalpAssignPCISlotResources,
NULL,
NULL
};
/* TYPE 1 FUNCTIONS **********************************************************/
VOID
NTAPI
HalpPCISynchronizeType1(IN PBUS_HANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PKIRQL Irql,
IN PPCI_TYPE1_CFG_BITS PciCfg1)
{
/* Setup the PCI Configuration Register */
PciCfg1->u.AsULONG = 0;
PciCfg1->u.bits.BusNumber = BusHandler->BusNumber;
PciCfg1->u.bits.DeviceNumber = Slot.u.bits.DeviceNumber;
PciCfg1->u.bits.FunctionNumber = Slot.u.bits.FunctionNumber;
PciCfg1->u.bits.Enable = TRUE;
/* Acquire the lock */
*Irql = KfRaiseIrql(HIGH_LEVEL);
KiAcquireSpinLock(&HalpPCIConfigLock);
}
VOID
NTAPI
HalpPCIReleaseSynchronzationType1(IN PBUS_HANDLER BusHandler,
IN KIRQL Irql)
{
PCI_TYPE1_CFG_BITS PciCfg1;
/* Clear the PCI Configuration Register */
PciCfg1.u.AsULONG = 0;
WRITE_PORT_ULONG(((PPCIPBUSDATA)BusHandler->BusData)->Config.Type1.Address,
PciCfg1.u.AsULONG);
/* Release the lock */
KiReleaseSpinLock(&HalpPCIConfigLock);
KfLowerIrql(Irql);
}
TYPE1_READ(HalpPCIReadUcharType1, UCHAR)
TYPE1_READ(HalpPCIReadUshortType1, USHORT)
TYPE1_READ(HalpPCIReadUlongType1, ULONG)
TYPE1_WRITE(HalpPCIWriteUcharType1, UCHAR)
TYPE1_WRITE(HalpPCIWriteUshortType1, USHORT)
TYPE1_WRITE(HalpPCIWriteUlongType1, ULONG)
/* TYPE 2 FUNCTIONS **********************************************************/
VOID
NTAPI
HalpPCISynchronizeType2(IN PBUS_HANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PKIRQL Irql,
IN PPCI_TYPE2_ADDRESS_BITS PciCfg)
{
PCI_TYPE2_CSE_BITS PciCfg2Cse;
PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData;
/* Setup the configuration register */
PciCfg->u.AsUSHORT = 0;
PciCfg->u.bits.Agent = (USHORT)Slot.u.bits.DeviceNumber;
PciCfg->u.bits.AddressBase = (USHORT)BusData->Config.Type2.Base;
/* Acquire the lock */
*Irql = KfRaiseIrql(HIGH_LEVEL);
KiAcquireSpinLock(&HalpPCIConfigLock);
/* Setup the CSE Register */
PciCfg2Cse.u.AsUCHAR = 0;
PciCfg2Cse.u.bits.Enable = TRUE;
PciCfg2Cse.u.bits.FunctionNumber = (UCHAR)Slot.u.bits.FunctionNumber;
PciCfg2Cse.u.bits.Key = -1;
/* Write the bus number and CSE */
WRITE_PORT_UCHAR(BusData->Config.Type2.Forward,
(UCHAR)BusHandler->BusNumber);
WRITE_PORT_UCHAR(BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
}
VOID
NTAPI
HalpPCIReleaseSynchronzationType2(IN PBUS_HANDLER BusHandler,
IN KIRQL Irql)
{
PCI_TYPE2_CSE_BITS PciCfg2Cse;
PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData;
/* Clear CSE and bus number */
PciCfg2Cse.u.AsUCHAR = 0;
WRITE_PORT_UCHAR(BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
WRITE_PORT_UCHAR(BusData->Config.Type2.Forward, 0);
/* Release the lock */
KiReleaseSpinLock(&HalpPCIConfigLock);
KfLowerIrql(Irql);
}
TYPE2_READ(HalpPCIReadUcharType2, UCHAR)
TYPE2_READ(HalpPCIReadUshortType2, USHORT)
TYPE2_READ(HalpPCIReadUlongType2, ULONG)
TYPE2_WRITE(HalpPCIWriteUcharType2, UCHAR)
TYPE2_WRITE(HalpPCIWriteUshortType2, USHORT)
TYPE2_WRITE(HalpPCIWriteUlongType2, ULONG)
/* PCI CONFIGURATION SPACE ***************************************************/
VOID
NTAPI
HalpPCIConfig(IN PBUS_HANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PUCHAR Buffer,
IN ULONG Offset,
IN ULONG Length,
IN FncConfigIO *ConfigIO)
{
KIRQL OldIrql;
ULONG i;
UCHAR State[20];
/* Synchronize the operation */
PCIConfigHandler.Synchronize(BusHandler, Slot, &OldIrql, State);
/* Loop every increment */
while (Length)
{
/* Find out the type of read/write we need to do */
i = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)];
/* Do the read/write and return the number of bytes */
i = ConfigIO[i]((PPCIPBUSDATA)BusHandler->BusData,
State,
Buffer,
Offset);
/* Increment the buffer position and offset, and decrease the length */
Offset += i;
Buffer += i;
Length -= i;
}
/* Release the lock and PCI bus */
PCIConfigHandler.ReleaseSynchronzation(BusHandler, OldIrql);
}
VOID
NTAPI
HalpReadPCIConfig(IN PBUS_HANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length)
{
/* Validate the PCI Slot */
if (!HalpValidPCISlot(BusHandler, Slot))
{
/* Fill the buffer with invalid data */
RtlFillMemory(Buffer, Length, -1);
}
else
{
/* Send the request */
HalpPCIConfig(BusHandler,
Slot,
Buffer,
Offset,
Length,
PCIConfigHandler.ConfigRead);
}
}
VOID
NTAPI
HalpWritePCIConfig(IN PBUS_HANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length)
{
/* Validate the PCI Slot */
if (HalpValidPCISlot(BusHandler, Slot))
{
/* Send the request */
HalpPCIConfig(BusHandler,
Slot,
Buffer,
Offset,
Length,
PCIConfigHandler.ConfigWrite);
}
}
BOOLEAN
NTAPI
HalpValidPCISlot(IN PBUS_HANDLER BusHandler,
IN PCI_SLOT_NUMBER Slot)
{
PCI_SLOT_NUMBER MultiSlot;
PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData;
UCHAR HeaderType;
ULONG Device;
/* Simple validation */
if (Slot.u.bits.Reserved) return FALSE;
if (Slot.u.bits.DeviceNumber >= BusData->MaxDevice) return FALSE;
/* Function 0 doesn't need checking */
if (!Slot.u.bits.FunctionNumber) return TRUE;
/* Functions 0+ need Multi-Function support, so check the slot */
Device = Slot.u.bits.DeviceNumber;
MultiSlot = Slot;
MultiSlot.u.bits.FunctionNumber = 0;
/* Send function 0 request to get the header back */
HalpReadPCIConfig(BusHandler,
MultiSlot,
&HeaderType,
FIELD_OFFSET(PCI_COMMON_CONFIG, HeaderType),
sizeof(UCHAR));
/* Now make sure the header is multi-function */
if (!(HeaderType & PCI_MULTIFUNCTION) || (HeaderType == 0xFF)) return FALSE;
return TRUE;
}
/* HAL PCI CALLBACKS *********************************************************/
ULONG
NTAPI
HalpGetPCIData(IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN PCI_SLOT_NUMBER Slot,
IN PUCHAR Buffer,
IN ULONG Offset,
IN ULONG Length)
{
UCHAR PciBuffer[PCI_COMMON_HDR_LENGTH];
PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)PciBuffer;
ULONG Len = 0;
/* Normalize the length */
if (Length > sizeof(PCI_COMMON_CONFIG)) Length = sizeof(PCI_COMMON_CONFIG);
/* Check if this is a vendor-specific read */
if (Offset >= PCI_COMMON_HDR_LENGTH)
{
/* Read the header */
HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, sizeof(ULONG));
/* Make sure the vendor is valid */
if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0;
}
else
{
/* Read the entire header */
Len = PCI_COMMON_HDR_LENGTH;
HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, Len);
/* Validate the vendor ID */
if (PciConfig->VendorID == PCI_INVALID_VENDORID)
{
/* It's invalid, but we want to return this much */
PciConfig->VendorID = PCI_INVALID_VENDORID;
Len = sizeof(USHORT);
}
/* Now check if there's space left */
if (Len < Offset) return 0;
/* There is, so return what's after the offset and normalize */
Len -= Offset;
if (Len > Length) Len = Length;
/* Copy the data into the caller's buffer */
RtlMoveMemory(Buffer, PciBuffer + Offset, Len);
/* Update buffer and offset, decrement total length */
Offset += Len;
Buffer += Len;
Length -= Len;
}
/* Now we still have something to copy */
if (Length)
{
/* Check if it's vendor-specific data */
if (Offset >= PCI_COMMON_HDR_LENGTH)
{
/* Read it now */
HalpReadPCIConfig(BusHandler, Slot, Buffer, Offset, Length);
Len += Length;
}
}
/* Update the total length read */
return Len;
}
ULONG
NTAPI
HalpSetPCIData(IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN PCI_SLOT_NUMBER Slot,
IN PUCHAR Buffer,
IN ULONG Offset,
IN ULONG Length)
{
UCHAR PciBuffer[PCI_COMMON_HDR_LENGTH];
PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)PciBuffer;
ULONG Len = 0;
/* Normalize the length */
if (Length > sizeof(PCI_COMMON_CONFIG)) Length = sizeof(PCI_COMMON_CONFIG);
/* Check if this is a vendor-specific read */
if (Offset >= PCI_COMMON_HDR_LENGTH)
{
/* Read the header */
HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, sizeof(ULONG));
/* Make sure the vendor is valid */
if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0;
}
else
{
/* Read the entire header and validate the vendor ID */
Len = PCI_COMMON_HDR_LENGTH;
HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, Len);
if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0;
/* Return what's after the offset and normalize */
Len -= Offset;
if (Len > Length) Len = Length;
/* Copy the specific caller data */
RtlMoveMemory(PciBuffer + Offset, Buffer, Len);
/* Write the actual configuration data */
HalpWritePCIConfig(BusHandler, Slot, PciBuffer + Offset, Offset, Len);
/* Update buffer and offset, decrement total length */
Offset += Len;
Buffer += Len;
Length -= Len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -