2020-09-30 17:17:25 +02:00

389 lines
8.9 KiB
C

/*++
Copyright (c) 2000-2001 Microsoft Corporation
Module Name:
pcispace.c
Abstract:
This module implements the routines to interface with PCI configuration
space.
--*/
#include "halp.h"
//
// Function prototype for PCI configuration space accessors.
//
typedef
ULONG
(*PHAL_PCISPACE_ACCESS_ROUTINE)(
IN PCI_TYPE1_CFG_BITS CfgBits,
IN ULONG RegisterNumber,
OUT PVOID Buffer
);
ULONG
HalpReadPCISpaceUchar(
IN PCI_TYPE1_CFG_BITS CfgBits,
IN ULONG RegisterNumber,
OUT PVOID Buffer
)
/*++
Routine Description:
This routine reads one byte from PCI configuration space.
Arguments:
CfgBits - Specifies the bus, device, and function number to read from.
RegisterNumber - Specifies the register number to transfer.
Buffer - Specifies the location to receive the data read.
Return Value:
The number of bytes read from PCI configuration space.
--*/
{
ULONG RegisterByteOffset;
RegisterByteOffset = RegisterNumber % sizeof(ULONG);
CfgBits.u.bits.RegisterNumber = RegisterNumber / sizeof(ULONG);
_outpd(PCI_TYPE1_ADDR_PORT, CfgBits.u.AsULONG);
*((PUCHAR)Buffer) = (UCHAR)_inp(PCI_TYPE1_DATA_PORT + RegisterByteOffset);
return sizeof(UCHAR);
}
ULONG
HalpReadPCISpaceUshort(
IN PCI_TYPE1_CFG_BITS CfgBits,
IN ULONG RegisterNumber,
OUT PVOID Buffer
)
/*++
Routine Description:
This routine reads two bytes from PCI configuration space.
Arguments:
CfgBits - Specifies the bus, device, and function number to read from.
RegisterNumber - Specifies the register number to transfer.
Buffer - Specifies the location to receive the data read.
Return Value:
The number of bytes read from PCI configuration space.
--*/
{
ULONG RegisterByteOffset;
RegisterByteOffset = RegisterNumber % sizeof(ULONG);
CfgBits.u.bits.RegisterNumber = RegisterNumber / sizeof(ULONG);
_outpd(PCI_TYPE1_ADDR_PORT, CfgBits.u.AsULONG);
*((PUSHORT)Buffer) = (USHORT)_inpw(PCI_TYPE1_DATA_PORT + RegisterByteOffset);
return sizeof(USHORT);
}
ULONG
HalpReadPCISpaceUlong(
IN PCI_TYPE1_CFG_BITS CfgBits,
IN ULONG RegisterNumber,
OUT PVOID Buffer
)
/*++
Routine Description:
This routine reads four bytes from PCI configuration space.
Arguments:
CfgBits - Specifies the bus, device, and function number to read from.
RegisterNumber - Specifies the register number to transfer.
Buffer - Specifies the location to receive the data read.
Return Value:
The number of bytes read from PCI configuration space.
--*/
{
ASSERT((RegisterNumber % sizeof(ULONG)) == 0);
CfgBits.u.bits.RegisterNumber = RegisterNumber / sizeof(ULONG);
_outpd(PCI_TYPE1_ADDR_PORT, CfgBits.u.AsULONG);
*((PULONG)Buffer) = _inpd(PCI_TYPE1_DATA_PORT);
return sizeof(ULONG);
}
ULONG
HalpWritePCISpaceUchar(
IN PCI_TYPE1_CFG_BITS CfgBits,
IN ULONG RegisterNumber,
IN PVOID Buffer
)
/*++
Routine Description:
This routine writes one byte to PCI configuration space.
Arguments:
CfgBits - Specifies the bus, device, and function number to write to.
RegisterNumber - Specifies the register number to transfer.
Buffer - Specifies the location that has the data to write out.
Return Value:
The number of bytes written to PCI configuration space.
--*/
{
ULONG RegisterByteOffset;
RegisterByteOffset = RegisterNumber % sizeof(ULONG);
CfgBits.u.bits.RegisterNumber = RegisterNumber / sizeof(ULONG);
_outpd(PCI_TYPE1_ADDR_PORT, CfgBits.u.AsULONG);
_outp(PCI_TYPE1_DATA_PORT + RegisterByteOffset, *((PUCHAR)Buffer));
return sizeof(UCHAR);
}
ULONG
HalpWritePCISpaceUshort(
IN PCI_TYPE1_CFG_BITS CfgBits,
IN ULONG RegisterNumber,
IN PVOID Buffer
)
/*++
Routine Description:
This routine writes two bytes to PCI configuration space.
Arguments:
CfgBits - Specifies the bus, device, and function number to write to.
RegisterNumber - Specifies the register number to transfer.
Buffer - Specifies the location that has the data to write out.
Return Value:
The number of bytes written to PCI configuration space.
--*/
{
ULONG RegisterByteOffset;
RegisterByteOffset = RegisterNumber % sizeof(ULONG);
CfgBits.u.bits.RegisterNumber = RegisterNumber / sizeof(ULONG);
_outpd(PCI_TYPE1_ADDR_PORT, CfgBits.u.AsULONG);
_outpw(PCI_TYPE1_DATA_PORT + RegisterByteOffset, *((PUSHORT)Buffer));
return sizeof(USHORT);
}
ULONG
HalpWritePCISpaceUlong(
IN PCI_TYPE1_CFG_BITS CfgBits,
IN ULONG RegisterNumber,
IN PVOID Buffer
)
/*++
Routine Description:
This routine writes four bytes to PCI configuration space.
Arguments:
CfgBits - Specifies the bus, device, and function number to write to.
RegisterNumber - Specifies the register number to transfer.
Buffer - Specifies the location that has the data to write out.
Return Value:
The number of bytes written to PCI configuration space.
--*/
{
ASSERT((RegisterNumber % sizeof(ULONG)) == 0);
CfgBits.u.bits.RegisterNumber = RegisterNumber / sizeof(ULONG);
_outpd(PCI_TYPE1_ADDR_PORT, CfgBits.u.AsULONG);
_outpd(PCI_TYPE1_DATA_PORT, *((PULONG)Buffer));
return sizeof(ULONG);
}
//
// Array of PCI configuration space read routines.
//
const PHAL_PCISPACE_ACCESS_ROUTINE HalpPCISpaceReaders[] = {
HalpReadPCISpaceUlong,
HalpReadPCISpaceUchar,
HalpReadPCISpaceUshort
};
//
// Array of PCI configuration space write routines.
//
const PHAL_PCISPACE_ACCESS_ROUTINE HalpPCISpaceWriters[] = {
HalpWritePCISpaceUlong,
HalpWritePCISpaceUchar,
HalpWritePCISpaceUshort
};
//
// Matrix of indexes into the above read and write routine arrays in order to
// access a given byte offset and transfer length.
//
const UCHAR HalpPCISpaceAccessMatrix[4][4] = {
{0, 1, 2, 2},
{1, 1, 1, 1},
{2, 1, 2, 2},
{1, 1, 1, 1}
};
VOID
HalReadWritePCISpace(
IN ULONG BusNumber,
IN ULONG SlotNumber,
IN ULONG RegisterNumber,
IN PVOID Buffer,
IN ULONG Length,
IN BOOLEAN WritePCISpace
)
/*++
Routine Description:
This routine reads from or writes to a buffer with PCI configuration space.
Arguments:
BusNumber - Specifies the desired PCI bus number.
SlotNumber - Specifies the desired PCI device and function number.
RegisterNumber - Specifies the desired starting PCI register number.
Buffer - Specifies the buffer to receive the data or supply the data for the
transfer.
Length - Specifies the number of bytes to transfer.
WritePCISpace - Specifies TRUE if data should be written to PCI
configuration space, else FALSE if data should be read from PCI
configuration space.
Return Value:
None.
--*/
{
PCI_SLOT_NUMBER PCISlotNumber;
PCI_TYPE1_CFG_BITS CfgBits;
#if DBG
USHORT DbgVendorID;
#endif
const PHAL_PCISPACE_ACCESS_ROUTINE *PCISpaceAccessors;
ULONG BytesTransferred;
UCHAR AccessIndex;
ASSERT(BusNumber <= PCI_MAX_BRIDGE_NUMBER);
ASSERT(RegisterNumber < sizeof(PCI_COMMON_CONFIG));
//
// Initialize the static portion of the configuration bits.
//
PCISlotNumber.u.AsULONG = SlotNumber;
CfgBits.u.AsULONG = 0;
CfgBits.u.bits.BusNumber = BusNumber;
CfgBits.u.bits.DeviceNumber = PCISlotNumber.u.bits.DeviceNumber;
CfgBits.u.bits.FunctionNumber = PCISlotNumber.u.bits.FunctionNumber;
CfgBits.u.bits.Enable = 1;
//
// Synchronize access to PCI configuration space by disabling interrupts.
//
_disable();
#if DBG
//
// If we're writing out to PCI space, then assert that there's a device
// connected to the supplied bus/device/function number.
//
if (WritePCISpace) {
HalpReadPCISpaceUshort(CfgBits, 0, &DbgVendorID);
ASSERT(DbgVendorID != PCI_INVALID_VENDORID);
}
#endif
//
// Determine which set of function pointers to use to access PCI
// configuration space.
//
PCISpaceAccessors = WritePCISpace ? HalpPCISpaceWriters : HalpPCISpaceReaders;
//
// Transfer the data to or from PCI configuration space.
//
while (Length > 0) {
AccessIndex = HalpPCISpaceAccessMatrix[RegisterNumber % sizeof(ULONG)][Length % sizeof(ULONG)];
BytesTransferred = PCISpaceAccessors[AccessIndex](CfgBits,
RegisterNumber, Buffer);
RegisterNumber += BytesTransferred;
Buffer = (PUCHAR)Buffer + BytesTransferred;
Length -= BytesTransferred;
}
//
// Reenable interrupts now that we're finished accessing PCI configuration
// space.
//
_enable();
}