Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1008 lines
25 KiB

/*++
Copyright (c) 1995 DeskStation Technology
Module Name:
pcisup.c
Abstract:
This module contains the routines that support PCI configuration cycles and
PCI interrupts.
Author:
Michael D. Kinney 2-May-1995
Environment:
Kernel mode
Revision History:
--*/
#include "halp.h"
#include "pci.h"
#include "pcip.h"
#define SP_VIRTUAL_BASE 0xffffa000
#define INVALID_PCI_CONFIGURATION_ADDRESS (0x00000000)
#define NO_PCI_DEVSEL_DATA_VALUE (0xffffffff)
//
// The following tables are used to map between PCI interrupt pins, PCI interrupt lines,
// and virtual ISA interrupt indexes. The Uniflex architecture uses a 16 bit interrupt
// controller for ISA interrupts and all PCI interrupts.
// InterruptLine values between 0x10 and 0x20 are reserved
// for PCI devices. InterruptLine values between 0x00 and 0x10 are reserved for ISA IRQs.
//
UCHAR Treb13InterruptLineToBit[0x11] = {0,1,2,3,8,9,10,11,12,12,12,12,12,12,4,5,12};
UCHAR Treb13BitToInterruptLine[12] = {0x00,0x01,0x02,0x03,0x0e,0x0f,0x00,0x00,0x04,0x05,0x06,0x07};
UCHAR Treb13InterruptLineToVirtualIsa[0x11] = {0,1,2,3,8,9,10,11,0,0,0,0,0,0,0,0,0};
UCHAR Treb13VirtualIsaToInterruptLine[0x10] = {0x10,0x11,0x12,0x13,0,0,0,0,0x14,0x15,0x16,0x17,0,0,0,0};
UCHAR Treb20InterruptLineToBit[0x11] = {3,1,2,8,9,10,0,5,11,12,12,12,12,12,12,12,12};
UCHAR Treb20BitToInterruptLine[12] = {0x06,0x01,0x02,0x00,0x00,0x07,0x00,0x00,0x03,0x04,0x05,0x08};
UCHAR Treb20InterruptLineToVirtualIsa[0x11] = {0,1,2,3,8,9,10,11,0,0,0,0,0,0,0,0,0};
UCHAR Treb20VirtualIsaToInterruptLine[0x10] = {0x10,0x11,0x12,0x13,0,0,0,0,0x14,0x15,0x16,0x17,0,0,0,0};
//
// Interrupt mask for all active PCI interrupts including ISA Bus PICs
//
static volatile ULONG HalpPciInterruptMask;
//
// Interrupt mask for PCI interrupts that have been connected through device drivers.
//
static volatile ULONG HalpPciDeviceInterruptMask;
//
// Interrupt mask showing which bit cooresponds to ISA Bus #0 PIC
//
static volatile ULONG HalpEisaInterruptMask;
//
// Interrupt mask showing which bit cooresponds to ISA Bus #1 PIC
//
static volatile ULONG HalpEisa1InterruptMask;
PVOID HalpAllocateIoMapping(
LONGLONG BaseAddress
)
{
ENTRYLO HalpPte[2];
ULONG KdPortEntry;
//
// Map the PCI Configuration register into the system virtual address space by loading
// a TB entry.
//
HalpPte[0].PFN = (ULONG)(BaseAddress >> 12);
HalpPte[0].G = 1;
HalpPte[0].V = 1;
HalpPte[0].D = 1;
//
// Allocate a TB entry, set the uncached policy in the PTE that will
// map the serial controller, and initialize the second PTE.
//
KdPortEntry = HalpAllocateTbEntry();
HalpPte[0].C = UNCACHED_POLICY;
HalpPte[1].PFN = 0;
HalpPte[1].G = 1;
HalpPte[1].V = 0;
HalpPte[1].D = 0;
HalpPte[1].C = 0;
//
// Map the PCI Configuration register through a fixed TB entry.
//
KeFillFixedEntryTb((PHARDWARE_PTE)&HalpPte[0],
(PVOID)SP_VIRTUAL_BASE,
KdPortEntry);
return((PVOID)(SP_VIRTUAL_BASE + (ULONG)(BaseAddress & 0xfff)));
}
VOID HalpFreeIoMapping(
VOID
)
{
HalpFreeTbEntry();
}
VOID
HalpWritePciInterruptMask (
VOID
)
/*++
Routine Description:
This function writes the interrupt mask register for PCI interrupts.
Arguments:
None.
Return Value:
None.
--*/
{
WRITE_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x00,HalpPciInterruptMask&0x0f);
WRITE_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x08,(HalpPciInterruptMask>>4)&0x0f);
WRITE_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x10,(HalpPciInterruptMask>>8)&0x0f);
}
ULONG
HalpReadPciInterruptStatus (
VOID
)
/*++
Routine Description:
This function reads the interrupt status register for PCI interrupts.
Arguments:
None.
Return Value:
The lower 12 bits contain the status of each interrupt line going to the PCI
interrupt controller.
--*/
{
return( (READ_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x00)<<0) & 0x00f |
(READ_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x08)<<4) & 0x030 |
(READ_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x10)<<8) & 0xf00 );
}
ULONG
HalpGetMemoryMode (
VOID
)
/*++
Routine Description:
This function returns the status of the MemoryMode bit that is embedded within
the PCI interrupt controller. The status of this bit must be preserved on all
writes to the PCI interrupt mask register.
Arguments:
None.
Return Value:
None.
--*/
{
return( (READ_REGISTER_ULONG((ULONG)PciInterruptRegisterBase+0x08) & 0x08) << 4 );
}
VOID
HalpSetPciInterruptBit (
ULONG Bit
)
/*++
Routine Description:
This function sets a bit in the PCI interrupt mask and writes the new mask
to the interrupt controller.
Arguments:
Bit - The bit number to set in the PCI interrupt mask.
Return Value:
None.
--*/
{
if (Bit==6 || Bit==7 || Bit>=12) {
return;
}
HalpPciDeviceInterruptMask = HalpPciDeviceInterruptMask | (1<<Bit);
HalpPciInterruptMask = HalpPciInterruptMask | (1<<Bit);
HalpWritePciInterruptMask();
}
VOID
HalpClearPciInterruptBit (
ULONG Bit
)
/*++
Routine Description:
This function clears a bit in the PCI interrupt mask and writes the new mask
to the interrupt controller.
Arguments:
Bit - The bit number to clear from the PCI interrupt mask.
Return Value:
None.
--*/
{
if (Bit==6 || Bit==7 || Bit>=12) {
return;
}
HalpPciDeviceInterruptMask = HalpPciDeviceInterruptMask & ~(1<<Bit);
HalpPciInterruptMask = HalpPciInterruptMask & ~(1<<Bit);
HalpWritePciInterruptMask();
}
VOID
HalpEnablePciInterrupt (
IN ULONG Vector
)
/*++
Routine Description:
This function enables a PCI interrupt.
Arguments:
Vector - Specifies the interrupt to enable.
Return Value:
None.
--*/
{
if (Vector >= UNIFLEX_PCI_VECTORS && Vector <= UNIFLEX_MAXIMUM_PCI_VECTOR) {
HalpSetPciInterruptBit(HalpInterruptLineToBit[Vector-UNIFLEX_PCI_VECTORS]);
}
}
VOID
HalpDisablePciInterrupt (
IN ULONG Vector
)
/*++
Routine Description:
This function disables a PCI interrupt.
Arguments:
Vector - Specifies the interrupt to disable.
Return Value:
None.
--*/
{
if (Vector >= UNIFLEX_PCI_VECTORS && Vector <= UNIFLEX_MAXIMUM_PCI_VECTOR) {
HalpClearPciInterruptBit(HalpInterruptLineToBit[Vector-UNIFLEX_PCI_VECTORS]);
}
}
ULONG
HalpVirtualIsaInterruptToInterruptLine (
IN ULONG Index
)
/*++
Routine Description:
This function maps a virtual ISA interrupt to a PCI interrupt line value.
This provides the ability to use an ISA device driver on a PCI device.
Arguments:
Index - Index into a platform specific table that maps PCI interrupts to
virtual ISA interrupts.
Return Value:
None.
--*/
{
return(HalpVirtualIsaToInterruptLine[Index]);
}
BOOLEAN
HalpEisa0Dispatch(
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext
)
/*++
Routine Description:
This is the interrupt dispatcher for all ISA Bus #0 interrupts.
Arguments:
Interrupt - Supplies a pointer to the interrupt object.
ServiceContext - not used.
Return Value:
Returns the value returned from the second level routine.
--*/
{
return(HalpEisaDispatch(Interrupt,ServiceContext,0));
}
BOOLEAN
HalpPciDispatch(
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext
)
/*++
Routine Description:
This is the interrupt dispatcher for all PCI interrupts.
Arguments:
Interrupt - Supplies a pointer to the interrupt object.
ServiceContext - not used.
Return Value:
Returns the value returned from the second level routine.
--*/
{
ULONG PciInterruptStatus;
PULONG dispatchCode;
PKINTERRUPT interruptObject;
USHORT PCRInOffset;
BOOLEAN returnValue = FALSE;
ULONG i;
//
// Get the active interrupt bits
//
PciInterruptStatus = HalpReadPciInterruptStatus();
//
// See if this is the interrupt for ISA Bus #0 PIC
//
if (PciInterruptStatus & HalpEisaInterruptMask) {
returnValue = HalpEisaDispatch(Interrupt,ServiceContext,0);
//
// If there really was an interrupt on ISA Bus #0, then return now.
//
if (returnValue) {
return(returnValue);
}
}
//
// See if this is the interrupt for ISA Bus #1 PIC
//
if (PciInterruptStatus & HalpEisa1InterruptMask) {
returnValue = HalpEisaDispatch(Interrupt,ServiceContext,1);
//
// If there really was an interrupt on ISA Bus #1, then return now.
//
if (returnValue) {
return(returnValue);
}
}
//
// Only keep interrupt bits that have been connected by device drivers.
//
PciInterruptStatus &= HalpPciDeviceInterruptMask;
//
// Dispatch to the ISRs of interrupts that have been connected by device drivers.
//
for(i=0;i<12;i++) {
if (PciInterruptStatus & (1<<i)) {
PCRInOffset = UNIFLEX_PCI_VECTORS + HalpBitToInterruptLine[i];
//
// Dispatch to the secondary interrupt service routine.
//
dispatchCode = (PULONG)(PCR->InterruptRoutine[PCRInOffset]);
interruptObject = CONTAINING_RECORD(dispatchCode,
KINTERRUPT,
DispatchCode);
returnValue =
((PSECONDARY_DISPATCH)interruptObject->DispatchAddress)
(interruptObject);
}
}
return(returnValue);
}
UCHAR HalpGetInterruptLine(ULONG BusNumber,ULONG DeviceNumber,ULONG InterruptPin)
/*++
Routine Description:
This routine maps a PCI interrupt described by the device's bus number, device number, and
interrupt pin into the interrupt line value that is stored in the PCI config header.
Arguments:
BusNumber - PCI bus number of the device.
DeviceNumber - PCI device number of the device.
InterruptPin - PCI interrupt pin of the device (A=1,B=2,C=3,D=4).
Return Value:
Returns the PCI Interrupt Line value for the PCI device.
--*/
{
UCHAR InterruptLine;
if (HalpMotherboardType == TREBBIA13) {
if (BusNumber > 1)
{
BusNumber = 1;
}
switch (BusNumber<<16 | DeviceNumber<<8 | InterruptPin) {
case 0x010401 : InterruptLine = 0x10; break; // Bus 1, Device 4, Int A
case 0x010601 : InterruptLine = 0x11; break; // Bus 1, Device 6, Int A
case 0x010501 : InterruptLine = 0x12; break; // Bus 1, Device 5, Int A
case 0x010701 : InterruptLine = 0x13; break; // Bus 1, Device 7, Int A
case 0x010402 : InterruptLine = 0x17; break; // Bus 1, Device 4, Int B
case 0x010602 : InterruptLine = 0x14; break; // Bus 1, Device 6, Int B
case 0x010502 : InterruptLine = 0x14; break; // Bus 1, Device 5, Int B
case 0x010702 : InterruptLine = 0x17; break; // Bus 1, Device 7, Int B
case 0x010403 : InterruptLine = 0x15; break; // Bus 1, Device 4, Int C
case 0x010603 : InterruptLine = 0x15; break; // Bus 1, Device 6, Int C
case 0x010503 : InterruptLine = 0x15; break; // Bus 1, Device 5, Int C
case 0x010703 : InterruptLine = 0x15; break; // Bus 1, Device 7, Int C
case 0x010404 : InterruptLine = 0x16; break; // Bus 1, Device 4, Int D
case 0x010604 : InterruptLine = 0x16; break; // Bus 1, Device 6, Int D
case 0x010504 : InterruptLine = 0x16; break; // Bus 1, Device 5, Int D
case 0x010704 : InterruptLine = 0x16; break; // Bus 1, Device 7, Int D
case 0x000d01 : InterruptLine = 0x1e; break; // Bus 0, Device 13, Int A
case 0x000f01 : InterruptLine = 0x1f; break; // Bus 0, Device 15, Int A
case 0x001001 : InterruptLine = 0x20; break; // Bus 0, Device 16, Int A
default : InterruptLine = 0xff; break;
}
}
if (HalpMotherboardType == TREBBIA20) {
if (BusNumber == 0) {
return(0xff);
}
if (BusNumber >= HalpSecondPciBridgeBusNumber) {
BusNumber = 1;
} else {
BusNumber = 0;
}
switch (BusNumber<<16 | DeviceNumber<<8 | InterruptPin) {
case 0x000401 : InterruptLine = 0x20; break;
case 0x000501 :
case 0x000603 :
case 0x000704 : InterruptLine = 0x10; break;
case 0x000502 :
case 0x000604 :
case 0x000701 : InterruptLine = 0x11; break;
case 0x000503 :
case 0x000601 :
case 0x000702 : InterruptLine = 0x12; break;
case 0x000504 :
case 0x000602 :
case 0x000703 : InterruptLine = 0x13; break;
case 0x010401 :
case 0x010504 :
case 0x010603 : InterruptLine = 0x14; break;
case 0x010402 :
case 0x010501 :
case 0x010604 : InterruptLine = 0x15; break;
case 0x010403 :
case 0x010502 :
case 0x010601 : InterruptLine = 0x16; break;
case 0x010404 :
case 0x010503 :
case 0x010602 : InterruptLine = 0x17; break;
case 0x010701 : InterruptLine = 0x18; break;
default : InterruptLine = 0xff; break;
}
}
return(InterruptLine);
}
VOID
HalpConnectInterruptDispatchers (
VOID
)
/*++
Routine Description:
This function connects the PCI interrupt dispatch routine and enables
ISA interrupts so they will generate processor interrupts.
Arguments:
None.
Return Value:
None.
--*/
{
UCHAR InterruptLine;
//
// Initialize the EISA interrupt dispatcher and the PCI interrupt dispatcher
//
PCR->InterruptRoutine[UNIFLEX_PCI_DEVICE_LEVEL] = (PKINTERRUPT_ROUTINE)HalpPciDispatch;
PCR->InterruptRoutine[UNIFLEX_EISA_DEVICE_LEVEL] = (PKINTERRUPT_ROUTINE)HalpEisa0Dispatch;
DbgPrint("Intel82378 : Bus=%d Device=%d\n\r",HalpIntel82378BusNumber,HalpIntel82378DeviceNumber);
DbgPrint("SecondIntel82378 : Bus=%d Device=%d\n\r",HalpSecondPciBridgeBusNumber,HalpSecondIntel82378DeviceNumber);
InterruptLine = HalpGetInterruptLine(HalpIntel82378BusNumber,HalpIntel82378DeviceNumber,1);
HalpEisaInterruptMask = 0x0000;
if (InterruptLine != 0xff) {
HalpEisaInterruptMask = (1 << HalpInterruptLineToBit[InterruptLine-0x10]) & 0xffff;
}
InterruptLine = HalpGetInterruptLine(HalpSecondPciBridgeBusNumber,HalpSecondIntel82378DeviceNumber,1);
HalpEisa1InterruptMask = 0x0000;
if (InterruptLine != 0xff) {
HalpEisa1InterruptMask = (1 << HalpInterruptLineToBit[InterruptLine-0x10]) & 0xffff;
}
DbgPrint("HalpEisaInterruptMask = %08x\n\r",HalpEisaInterruptMask);
DbgPrint("HalpEisa1InterruptMask = %08x\n\r",HalpEisa1InterruptMask);
//
// Enable ISA Interrupts on Gambit's PIC
//
HalpPciInterruptMask = HalpGetMemoryMode();
HalpPciInterruptMask |= (HalpEisaInterruptMask | HalpEisa1InterruptMask);
HalpWritePciInterruptMask();
}
VOID
HalpDisableAllInterrupts(
VOID
)
/*++
Routine Description:
This function disables all external interrupt sources.
Arguments:
None.
Return Value:
None.
--*/
{
ULONG VirtualAddress;
VirtualAddress = (ULONG)HalpAllocateIoMapping(HalpIsaIoBasePhysical);
WRITE_REGISTER_UCHAR(VirtualAddress+0x21,0xff);
WRITE_REGISTER_UCHAR(VirtualAddress+0xa1,0xff);
HalpFreeIoMapping();
if (HalpNumberOfIsaBusses > 1) {
VirtualAddress = (ULONG)HalpAllocateIoMapping(HalpIsa1IoBasePhysical);
WRITE_REGISTER_UCHAR(VirtualAddress+0x21,0xff);
WRITE_REGISTER_UCHAR(VirtualAddress+0xa1,0xff);
HalpFreeIoMapping();
}
VirtualAddress = (ULONG)HalpAllocateIoMapping(GAMBIT_PCI_INTERRUPT_BASE_PHYSICAL);
HalpPciInterruptMask = ((READ_REGISTER_ULONG(VirtualAddress+0x08) & 0x08) << 4);
WRITE_REGISTER_ULONG(VirtualAddress+0x00,HalpPciInterruptMask&0x0f);
WRITE_REGISTER_ULONG(VirtualAddress+0x08,(HalpPciInterruptMask>>4)&0x0f);
WRITE_REGISTER_ULONG(VirtualAddress+0x10,(HalpPciInterruptMask>>8)&0x0f);
HalpFreeIoMapping();
HalpPciDeviceInterruptMask = 0x0000;
}
ULONG HalpPciConfigStructuresInitialized = FALSE;
PVOID HalpPciConfig0BaseAddress[0x20];
PVOID HalpPciConfig1BaseAddress[0x100];
PCI_CONFIGURATION_TYPES
HalpPCIConfigCycleType (IN ULONG BusNumber)
{
if (BusNumber == 0) {
return PciConfigType0;
} else if (BusNumber < PCIMaxBus) {
return PciConfigType1;
} else {
return PciConfigTypeInvalid;
}
}
VOID
HalpPCIConfigAddr (
IN ULONG BusNumber,
IN PCI_SLOT_NUMBER Slot,
PPCI_CFG_CYCLE_BITS pPciAddr
)
{
PCI_CONFIGURATION_TYPES ConfigType;
//
// If the Configuration Base Address tables have not been initialized, then
// initialize them to NULL.
//
if (HalpPciConfigStructuresInitialized == FALSE) {
ULONG i;
for(i=0;i<0x20;HalpPciConfig0BaseAddress[i++]=NULL);
for(i=0;i<0xff;HalpPciConfig1BaseAddress[i++]=NULL);
HalpPciConfigStructuresInitialized = TRUE;
}
ConfigType = HalpPCIConfigCycleType(BusNumber);
if (ConfigType == PciConfigType0) {
//
// Initialize PciAddr for a type 0 configuration cycle
//
//
// See if this is a nonexistant device on PCI Bus 0
//
if ( (1 << Slot.u.bits.DeviceNumber) & HalpNonExistentPciDeviceMask ) {
pPciAddr->u.AsULONG = INVALID_PCI_CONFIGURATION_ADDRESS;
return;
}
if (HalpPciConfig0BaseAddress[Slot.u.bits.DeviceNumber] == NULL) {
PHYSICAL_ADDRESS physicalAddress;
physicalAddress.QuadPart = HalpPciConfig0BasePhysical;
physicalAddress.QuadPart += (1 << (11 + Slot.u.bits.DeviceNumber));
HalpPciConfig0BaseAddress[Slot.u.bits.DeviceNumber] = MmMapIoSpace(physicalAddress,0x800,FALSE);
//
// If the mapping failed, then the return value is INVALID_PCI_CONFIGURATION_ADDRESS.
// This will cause Config Reads to return 0xffffffff, and Config Writes to do nothing.
//
if (HalpPciConfig0BaseAddress[Slot.u.bits.DeviceNumber] == NULL) {
pPciAddr->u.AsULONG = INVALID_PCI_CONFIGURATION_ADDRESS;
return;
}
}
pPciAddr->u.AsULONG = (ULONG)HalpPciConfig0BaseAddress[Slot.u.bits.DeviceNumber];
pPciAddr->u.AsULONG += ((Slot.u.bits.FunctionNumber & 0x07) << 8);
pPciAddr->u.bits0.Reserved1 = PciConfigType0;
#if DBG
DbgPrint("HalpPCIConfigAddr: Type 0 PCI Config Access @ %x\n", pPciAddr->u.AsULONG);
#endif // DBG
} else {
//
// See if this is a nonexistant PCI device on the otherside of the First PCI-PCI Bridge
//
if (BusNumber == 1 && (1 << Slot.u.bits.DeviceNumber) & HalpNonExistentPci1DeviceMask) {
pPciAddr->u.AsULONG = INVALID_PCI_CONFIGURATION_ADDRESS;
return;
}
//
// See if this is a nonexistant PCI device on the otherside of the Second PCI-PCI Bridge
//
if (BusNumber == HalpSecondPciBridgeBusNumber && (1 << Slot.u.bits.DeviceNumber) & HalpNonExistentPci2DeviceMask) {
pPciAddr->u.AsULONG = INVALID_PCI_CONFIGURATION_ADDRESS;
return;
}
//
// Initialize PciAddr for a type 1 configuration cycle
//
if (HalpPciConfig1BaseAddress[BusNumber] == NULL) {
PHYSICAL_ADDRESS physicalAddress;
physicalAddress.QuadPart = HalpPciConfig1BasePhysical;
physicalAddress.QuadPart += ((BusNumber & 0xff) << 16);
HalpPciConfig1BaseAddress[BusNumber] = MmMapIoSpace(physicalAddress,0x10000,FALSE);
//
// If the mapping failed, then the return value is INVALID_PCI_CONFIGURATION_ADDRESS.
// This will cause Config Reads to return 0xffffffff, and Config Writes to do nothing.
//
if (HalpPciConfig1BaseAddress[BusNumber] == NULL) {
pPciAddr->u.AsULONG = INVALID_PCI_CONFIGURATION_ADDRESS;
return;
}
}
pPciAddr->u.AsULONG = (ULONG)HalpPciConfig1BaseAddress[BusNumber];
pPciAddr->u.AsULONG += ((Slot.u.bits.DeviceNumber & 0x1f) << 11);
pPciAddr->u.AsULONG += ((Slot.u.bits.FunctionNumber & 0x07) << 8);
pPciAddr->u.bits0.Reserved1 = PciConfigType1;
#if DBG
DbgPrint("Type 1 PCI Config Access @ %x\n", pPciAddr->u.AsULONG);
#endif // DBG
}
return;
}
UCHAR
READ_CONFIG_UCHAR(
IN PVOID ConfigurationAddress,
IN ULONG ConfigurationType
)
{
if (((ULONG)ConfigurationAddress & 0xffffff00) == INVALID_PCI_CONFIGURATION_ADDRESS) {
return((UCHAR)NO_PCI_DEVSEL_DATA_VALUE);
}
return(READ_REGISTER_UCHAR(ConfigurationAddress));
}
USHORT
READ_CONFIG_USHORT(
IN PVOID ConfigurationAddress,
IN ULONG ConfigurationType
)
{
if (((ULONG)ConfigurationAddress & 0xffffff00) == INVALID_PCI_CONFIGURATION_ADDRESS) {
return((USHORT)NO_PCI_DEVSEL_DATA_VALUE);
}
return(READ_REGISTER_USHORT(ConfigurationAddress));
}
ULONG
READ_CONFIG_ULONG(
IN PVOID ConfigurationAddress,
IN ULONG ConfigurationType
)
{
if (((ULONG)ConfigurationAddress & 0xffffff00) == INVALID_PCI_CONFIGURATION_ADDRESS) {
return((ULONG)NO_PCI_DEVSEL_DATA_VALUE);
}
return(READ_REGISTER_ULONG(ConfigurationAddress));
}
VOID
WRITE_CONFIG_UCHAR(
IN PVOID ConfigurationAddress,
IN UCHAR ConfigurationData,
IN ULONG ConfigurationType
)
{
if (((ULONG)ConfigurationAddress & 0xffffff00) != INVALID_PCI_CONFIGURATION_ADDRESS) {
WRITE_REGISTER_UCHAR(ConfigurationAddress,ConfigurationData);
}
}
VOID
WRITE_CONFIG_USHORT(
IN PVOID ConfigurationAddress,
IN USHORT ConfigurationData,
IN ULONG ConfigurationType
)
{
if (((ULONG)ConfigurationAddress & 0xffffff00) != INVALID_PCI_CONFIGURATION_ADDRESS) {
WRITE_REGISTER_USHORT(ConfigurationAddress,ConfigurationData);
}
}
VOID
WRITE_CONFIG_ULONG(
IN PVOID ConfigurationAddress,
IN ULONG ConfigurationData,
IN ULONG ConfigurationType
)
{
if (((ULONG)ConfigurationAddress & 0xffffff00) != INVALID_PCI_CONFIGURATION_ADDRESS) {
WRITE_REGISTER_ULONG(ConfigurationAddress,ConfigurationData);
}
}
LONGLONG HalpMapPciConfigBaseAddress(
IN ULONG BusNumber,
IN ULONG DeviceNumber,
IN ULONG FunctionNumber,
IN ULONG Register
)
{
LONGLONG BaseAddress;
if (BusNumber == 0) {
BaseAddress = HalpPciConfig0BasePhysical +
(1 << (11+(DeviceNumber & 0x1f))) +
((FunctionNumber & 0x07) << 8) +
Register;
} else {
BaseAddress = HalpPciConfig1BasePhysical +
((BusNumber & 0xff) << 16) +
((DeviceNumber & 0x1f) << 11) +
((FunctionNumber & 0x07) << 8) +
Register;
}
return(BaseAddress);
}
ULONG HalpPciLowLevelConfigRead(
IN ULONG BusNumber,
IN ULONG DeviceNumber,
IN ULONG FunctionNumber,
IN ULONG Register
)
/*++
Routine Description:
This function allocates the resources needed to perform a single PCI
configuration read cycle. The read data is returned. For a MIPS processor,
a single TLB entry is borrowed so that I/O reads and writes can be performed
to PCI configuration space.
Return Value:
Data retuned by the PCI config cycle.
--*/
{
LONGLONG BaseAddress;
PVOID VirtualAddress;
ULONG ReturnValue;
BaseAddress = HalpMapPciConfigBaseAddress(BusNumber,DeviceNumber,FunctionNumber,Register&0xfc);
VirtualAddress = HalpAllocateIoMapping(BaseAddress);
ReturnValue = READ_REGISTER_ULONG(VirtualAddress);
HalpFreeIoMapping();
return(ReturnValue);
}
VOID HalpPostCard(UCHAR Value)
{
LONGLONG BaseAddress;
PVOID VirtualAddress;
BaseAddress = HalpMapPciConfigBaseAddress(HalpIntel82378BusNumber,HalpIntel82378DeviceNumber,0,0x4f);
VirtualAddress = HalpAllocateIoMapping(BaseAddress);
WRITE_REGISTER_UCHAR(VirtualAddress,0xcf);
HalpFreeIoMapping();
VirtualAddress = HalpAllocateIoMapping(HalpIsaIoBasePhysical + 0x420);
Value = (Value & 0x7f) | (READ_REGISTER_UCHAR(VirtualAddress) & 0x80);
HalpFreeIoMapping();
VirtualAddress = HalpAllocateIoMapping(HalpIsaIoBasePhysical + 0xc00);
WRITE_REGISTER_UCHAR(VirtualAddress,Value);
HalpFreeIoMapping();
BaseAddress = HalpMapPciConfigBaseAddress(HalpIntel82378BusNumber,HalpIntel82378DeviceNumber,0,0x4f);
VirtualAddress = HalpAllocateIoMapping(BaseAddress);
WRITE_REGISTER_UCHAR(VirtualAddress,0x4f);
HalpFreeIoMapping();
}