1402 lines
35 KiB
C
1402 lines
35 KiB
C
|
/*++
|
||
|
|
||
|
|
||
|
Copyright (c) 1989 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
ixpcidat.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Get/Set bus data routines for the PCI bus
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
Kernel mode
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "bootx86.h"
|
||
|
#include "arc.h"
|
||
|
#include "ixfwhal.h"
|
||
|
#include "ntconfig.h"
|
||
|
|
||
|
#include "pci.h"
|
||
|
|
||
|
//extern WCHAR rgzMultiFunctionAdapter[];
|
||
|
//extern WCHAR rgzConfigurationData[];
|
||
|
//extern WCHAR rgzIdentifier[];
|
||
|
//extern WCHAR rgzPCIIdentifier[];
|
||
|
|
||
|
//
|
||
|
// Hal specific PCI bus structures
|
||
|
//
|
||
|
|
||
|
typedef struct tagPCIPBUSDATA {
|
||
|
union {
|
||
|
struct {
|
||
|
PULONG Address;
|
||
|
ULONG Data;
|
||
|
} Type1;
|
||
|
struct {
|
||
|
PUCHAR CSE;
|
||
|
PUCHAR Forward;
|
||
|
ULONG Base;
|
||
|
} Type2;
|
||
|
} Config;
|
||
|
|
||
|
} PCIPBUSDATA, *PPCIPBUSDATA;
|
||
|
|
||
|
#define PciBitIndex(Dev,Fnc) (Fnc*32 + Dev);
|
||
|
#define PCI_CONFIG_TYPE(PciData) ((PciData)->HeaderType & ~PCI_MULTIFUNCTION)
|
||
|
|
||
|
#define BUSHANDLER _BUSHANDLER
|
||
|
#define PBUSHANDLER _PBUSHANDLER
|
||
|
|
||
|
// thunk for NtLdr
|
||
|
typedef struct {
|
||
|
ULONG NoBuses;
|
||
|
ULONG BusNumber;
|
||
|
PVOID BusData;
|
||
|
PCIPBUSDATA theBusData;
|
||
|
} BUSHANDLER, *PBUSHANDLER;
|
||
|
|
||
|
#define HalpPCIPin2Line(bus,rbus,slot,pcidata)
|
||
|
#define HalpPCILine2Pin(bus,rbus,slot,pcidata,pcidata2)
|
||
|
#define ExAllocatePool(a,l) FwAllocatePool(l)
|
||
|
// thunk for NtLdr
|
||
|
|
||
|
|
||
|
typedef ULONG (*FncConfigIO) (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PVOID State,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
);
|
||
|
|
||
|
typedef VOID (*FncSync) (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN PCI_SLOT_NUMBER Slot,
|
||
|
IN PKIRQL Irql,
|
||
|
IN PVOID State
|
||
|
);
|
||
|
|
||
|
typedef VOID (*FncReleaseSync) (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN KIRQL Irql
|
||
|
);
|
||
|
|
||
|
typedef struct {
|
||
|
FncSync Synchronize;
|
||
|
FncReleaseSync ReleaseSynchronzation;
|
||
|
FncConfigIO ConfigRead[3];
|
||
|
FncConfigIO ConfigWrite[3];
|
||
|
} CONFIG_HANDLER, *PCONFIG_HANDLER;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Prototypes
|
||
|
//
|
||
|
|
||
|
ULONG
|
||
|
HalpGetPCIData (
|
||
|
IN ULONG BusNumber,
|
||
|
IN PCI_SLOT_NUMBER SlotNumber,
|
||
|
IN PVOID Buffer,
|
||
|
IN ULONG Offset,
|
||
|
IN ULONG Length
|
||
|
);
|
||
|
|
||
|
ULONG
|
||
|
HalpSetPCIData (
|
||
|
IN ULONG BusNumber,
|
||
|
IN PCI_SLOT_NUMBER SlotNumber,
|
||
|
IN PVOID Buffer,
|
||
|
IN ULONG Offset,
|
||
|
IN ULONG Length
|
||
|
);
|
||
|
|
||
|
extern ULONG
|
||
|
HalpGetPCIInterruptVector (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN PBUSHANDLER RootHandler,
|
||
|
IN ULONG BusInterruptLevel,
|
||
|
IN ULONG BusInterruptVector,
|
||
|
OUT PKIRQL Irql,
|
||
|
OUT PKAFFINITY Affinity
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpAdjustPCIResourceList (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN PBUSHANDLER RootHandler,
|
||
|
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpAssignPCISlotResources (
|
||
|
IN ULONG BusNumber,
|
||
|
IN ULONG SlotNumber,
|
||
|
IN OUT PCM_RESOURCE_LIST *AllocatedResources
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
HalpInitializePciBuses (
|
||
|
VOID
|
||
|
);
|
||
|
|
||
|
//VOID
|
||
|
//HalpPCIPin2Line (
|
||
|
// IN PBUSHANDLER BusHandler,
|
||
|
// IN PBUSHANDLER RootHandler,
|
||
|
// IN PCI_SLOT_NUMBER Slot,
|
||
|
// IN PPCI_COMMON_CONFIG PciData
|
||
|
// );
|
||
|
//
|
||
|
//VOID
|
||
|
//HalpPCILine2Pin (
|
||
|
// IN PBUSHANDLER BusHandler,
|
||
|
// IN PBUSHANDLER RootHandler,
|
||
|
// IN PCI_SLOT_NUMBER SlotNumber,
|
||
|
// IN PPCI_COMMON_CONFIG PciNewData,
|
||
|
// IN PPCI_COMMON_CONFIG PciOldData
|
||
|
// );
|
||
|
|
||
|
BOOLEAN
|
||
|
HalpValidPCISlot (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN PCI_SLOT_NUMBER Slot
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
HalpReadPCIConfig (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN PCI_SLOT_NUMBER Slot,
|
||
|
IN PVOID Buffer,
|
||
|
IN ULONG Offset,
|
||
|
IN ULONG Length
|
||
|
);
|
||
|
|
||
|
|
||
|
VOID
|
||
|
HalpWritePCIConfig (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN PCI_SLOT_NUMBER Slot,
|
||
|
IN PVOID Buffer,
|
||
|
IN ULONG Offset,
|
||
|
IN ULONG Length
|
||
|
);
|
||
|
|
||
|
PBUSHANDLER
|
||
|
HalpGetPciBusHandler (
|
||
|
IN ULONG BusNumber
|
||
|
);
|
||
|
|
||
|
//-------------------------------------------------
|
||
|
|
||
|
VOID HalpPCISynchronizeType1 (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN PCI_SLOT_NUMBER Slot,
|
||
|
IN PKIRQL Irql,
|
||
|
IN PVOID State
|
||
|
);
|
||
|
|
||
|
VOID HalpPCIReleaseSynchronzationType1 (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN KIRQL Irql
|
||
|
);
|
||
|
|
||
|
ULONG HalpPCIReadUlongType1 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PVOID State,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
);
|
||
|
|
||
|
ULONG HalpPCIReadUcharType1 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PVOID State,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
);
|
||
|
|
||
|
ULONG HalpPCIReadUshortType1 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PVOID State,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
);
|
||
|
|
||
|
ULONG HalpPCIWriteUlongType1 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PVOID State,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
);
|
||
|
|
||
|
ULONG HalpPCIWriteUcharType1 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PVOID State,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
);
|
||
|
|
||
|
ULONG HalpPCIWriteUshortType1 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PVOID State,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
);
|
||
|
|
||
|
VOID HalpPCISynchronizeType2 (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN PCI_SLOT_NUMBER Slot,
|
||
|
IN PKIRQL Irql,
|
||
|
IN PVOID State
|
||
|
);
|
||
|
|
||
|
VOID HalpPCIReleaseSynchronzationType2 (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN KIRQL Irql
|
||
|
);
|
||
|
|
||
|
ULONG HalpPCIReadUlongType2 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PVOID State,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
);
|
||
|
|
||
|
ULONG HalpPCIReadUcharType2 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PVOID State,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
);
|
||
|
|
||
|
ULONG HalpPCIReadUshortType2 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PVOID State,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
);
|
||
|
|
||
|
ULONG HalpPCIWriteUlongType2 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PVOID State,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
);
|
||
|
|
||
|
ULONG HalpPCIWriteUcharType2 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PVOID State,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
);
|
||
|
|
||
|
ULONG HalpPCIWriteUshortType2 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PVOID State,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
);
|
||
|
|
||
|
|
||
|
#define DISABLE_INTERRUPTS() //_asm { cli }
|
||
|
#define ENABLE_INTERRUPTS() //_asm { sti }
|
||
|
|
||
|
|
||
|
//
|
||
|
// Globals
|
||
|
//
|
||
|
|
||
|
ULONG PCIMaxDevice;
|
||
|
BUSHANDLER PCIBusHandler;
|
||
|
|
||
|
CONFIG_HANDLER PCIConfigHandlers = {
|
||
|
HalpPCISynchronizeType1,
|
||
|
HalpPCIReleaseSynchronzationType1,
|
||
|
{
|
||
|
HalpPCIReadUlongType1, // 0
|
||
|
HalpPCIReadUcharType1, // 1
|
||
|
HalpPCIReadUshortType1 // 2
|
||
|
},
|
||
|
{
|
||
|
HalpPCIWriteUlongType1, // 0
|
||
|
HalpPCIWriteUcharType1, // 1
|
||
|
HalpPCIWriteUshortType1 // 2
|
||
|
}
|
||
|
};
|
||
|
|
||
|
CONFIG_HANDLER PCIConfigHandlersType2 = {
|
||
|
HalpPCISynchronizeType2,
|
||
|
HalpPCIReleaseSynchronzationType2,
|
||
|
{
|
||
|
HalpPCIReadUlongType2, // 0
|
||
|
HalpPCIReadUcharType2, // 1
|
||
|
HalpPCIReadUshortType2 // 2
|
||
|
},
|
||
|
{
|
||
|
HalpPCIWriteUlongType2, // 0
|
||
|
HalpPCIWriteUcharType2, // 1
|
||
|
HalpPCIWriteUshortType2 // 2
|
||
|
}
|
||
|
};
|
||
|
|
||
|
UCHAR PCIDeref[4][4] = { {0,1,2,2},{1,1,1,1},{2,1,2,2},{1,1,1,1} };
|
||
|
|
||
|
|
||
|
VOID
|
||
|
HalpPCIConfig (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN PCI_SLOT_NUMBER Slot,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset,
|
||
|
IN ULONG Length,
|
||
|
IN FncConfigIO *ConfigIO
|
||
|
);
|
||
|
|
||
|
|
||
|
VOID
|
||
|
HalpInitializePciBus (
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
PPCI_REGISTRY_INFO PCIRegInfo;
|
||
|
PPCIPBUSDATA BusData;
|
||
|
PBUSHANDLER Bus;
|
||
|
PCONFIGURATION_COMPONENT_DATA ConfigData;
|
||
|
PCM_PARTIAL_RESOURCE_LIST Desc;
|
||
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR PDesc;
|
||
|
ULONG i;
|
||
|
ULONG HwType;
|
||
|
|
||
|
Bus = &PCIBusHandler;
|
||
|
PCIBusHandler.BusData = &PCIBusHandler.theBusData;
|
||
|
|
||
|
PCIRegInfo = NULL; // not found
|
||
|
ConfigData = NULL; // start at begining
|
||
|
do {
|
||
|
ConfigData = KeFindConfigurationNextEntry (
|
||
|
FwConfigurationTree,
|
||
|
AdapterClass,
|
||
|
MultiFunctionAdapter,
|
||
|
NULL,
|
||
|
&ConfigData
|
||
|
);
|
||
|
|
||
|
if (ConfigData == NULL) {
|
||
|
// PCI info not found
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
if (ConfigData->ComponentEntry.Identifier == NULL ||
|
||
|
_stricmp (ConfigData->ComponentEntry.Identifier, "PCI") != 0) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
PCIRegInfo = NULL;
|
||
|
Desc = ConfigData->ConfigurationData;
|
||
|
PDesc = Desc->PartialDescriptors;
|
||
|
for (i = 0; i < Desc->Count; i++) {
|
||
|
if (PDesc->Type == CmResourceTypeDeviceSpecific) {
|
||
|
PCIRegInfo = (PPCI_REGISTRY_INFO) (PDesc+1);
|
||
|
break;
|
||
|
}
|
||
|
PDesc++;
|
||
|
}
|
||
|
} while (!PCIRegInfo) ;
|
||
|
|
||
|
//
|
||
|
// PCIRegInfo describes the system's PCI support as indicated
|
||
|
// by the BIOS.
|
||
|
//
|
||
|
|
||
|
HwType = PCIRegInfo->HardwareMechanism & 0xf;
|
||
|
|
||
|
switch (HwType) {
|
||
|
case 1:
|
||
|
// this is the default case
|
||
|
PCIMaxDevice = PCI_MAX_DEVICES;
|
||
|
break;
|
||
|
|
||
|
//
|
||
|
// Type2 does not work MP, nor does the default type2
|
||
|
// support more the 0xf device slots
|
||
|
//
|
||
|
|
||
|
case 2:
|
||
|
RtlMoveMemory (&PCIConfigHandlers,
|
||
|
&PCIConfigHandlersType2,
|
||
|
sizeof (PCIConfigHandlersType2));
|
||
|
PCIMaxDevice = 0x10;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
// unsupport type
|
||
|
PCIRegInfo->NoBuses = 0;
|
||
|
}
|
||
|
|
||
|
PCIBusHandler.NoBuses = PCIRegInfo->NoBuses;
|
||
|
if (PCIRegInfo->NoBuses) {
|
||
|
|
||
|
BusData = (PPCIPBUSDATA) Bus->BusData;
|
||
|
switch (HwType) {
|
||
|
case 1:
|
||
|
BusData->Config.Type1.Address = PCI_TYPE1_ADDR_PORT;
|
||
|
BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT;
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT;
|
||
|
BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT;
|
||
|
BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
PBUSHANDLER
|
||
|
HalpGetPciBusHandler (
|
||
|
IN ULONG BusNumber
|
||
|
)
|
||
|
{
|
||
|
if (PCIBusHandler.BusData == NULL) {
|
||
|
HalpInitializePciBus ();
|
||
|
}
|
||
|
|
||
|
if (BusNumber > PCIBusHandler.NoBuses) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
PCIBusHandler.BusNumber = BusNumber;
|
||
|
return &PCIBusHandler;
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
HalpGetPCIData (
|
||
|
IN ULONG BusNumber,
|
||
|
IN PCI_SLOT_NUMBER Slot,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset,
|
||
|
IN ULONG Length
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
The function returns the Pci bus data for a device.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
BusNumber - Indicates which bus.
|
||
|
|
||
|
VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word)
|
||
|
|
||
|
Buffer - Supplies the space to store the data.
|
||
|
|
||
|
Length - Supplies a count in bytes of the maximum amount to return.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns the amount of data stored into the buffer.
|
||
|
|
||
|
If this PCI slot has never been set, then the configuration information
|
||
|
returned is zeroed.
|
||
|
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PBUSHANDLER BusHandler;
|
||
|
PPCI_COMMON_CONFIG PciData;
|
||
|
UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
|
||
|
PPCIPBUSDATA BusData;
|
||
|
ULONG Len;
|
||
|
|
||
|
BusHandler = HalpGetPciBusHandler (BusNumber);
|
||
|
if (!BusHandler) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (Length > sizeof (PCI_COMMON_CONFIG)) {
|
||
|
Length = sizeof (PCI_COMMON_CONFIG);
|
||
|
}
|
||
|
|
||
|
Len = 0;
|
||
|
PciData = (PPCI_COMMON_CONFIG) iBuffer;
|
||
|
|
||
|
if (Offset >= PCI_COMMON_HDR_LENGTH) {
|
||
|
//
|
||
|
// The user did not request any data from the common
|
||
|
// header. Verify the PCI device exists, then continue
|
||
|
// in the device specific area.
|
||
|
//
|
||
|
|
||
|
HalpReadPCIConfig (BusHandler, Slot, PciData, 0, sizeof(ULONG));
|
||
|
|
||
|
if (PciData->VendorID == PCI_INVALID_VENDORID) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Caller requested at least some data within the
|
||
|
// common header. Read the whole header, effect the
|
||
|
// fields we need to and then copy the user's requested
|
||
|
// bytes from the header
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Read this PCI devices slot data
|
||
|
//
|
||
|
|
||
|
Len = PCI_COMMON_HDR_LENGTH;
|
||
|
HalpReadPCIConfig (BusHandler, Slot, PciData, 0, Len);
|
||
|
|
||
|
if (PciData->VendorID == PCI_INVALID_VENDORID) {
|
||
|
Len = 2; // only return invalid id
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Has this PCI device been configured?
|
||
|
//
|
||
|
|
||
|
BusData = (PPCIPBUSDATA) BusHandler->BusData;
|
||
|
HalpPCIPin2Line (BusHandler, RootHandler, Slot, PciData);
|
||
|
|
||
|
//
|
||
|
// Copy whatever data overlaps into the callers buffer
|
||
|
//
|
||
|
|
||
|
if (Len < Offset) {
|
||
|
// no data at caller's buffer
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
Len -= Offset;
|
||
|
if (Len > Length) {
|
||
|
Len = Length;
|
||
|
}
|
||
|
|
||
|
RtlMoveMemory(Buffer, iBuffer + Offset, Len);
|
||
|
|
||
|
Offset += Len;
|
||
|
Buffer += Len;
|
||
|
Length -= Len;
|
||
|
}
|
||
|
|
||
|
if (Length) {
|
||
|
if (Offset >= PCI_COMMON_HDR_LENGTH) {
|
||
|
//
|
||
|
// The remaining Buffer comes from the Device Specific
|
||
|
// area - put on the kitten gloves and read from it.
|
||
|
//
|
||
|
// Specific read/writes to the PCI device specific area
|
||
|
// are guarenteed:
|
||
|
//
|
||
|
// Not to read/write any byte outside the area specified
|
||
|
// by the caller. (this may cause WORD or BYTE references
|
||
|
// to the area in order to read the non-dword aligned
|
||
|
// ends of the request)
|
||
|
//
|
||
|
// To use a WORD access if the requested length is exactly
|
||
|
// a WORD long & WORD aligned.
|
||
|
//
|
||
|
// To use a BYTE access if the requested length is exactly
|
||
|
// a BYTE long.
|
||
|
//
|
||
|
|
||
|
HalpReadPCIConfig (BusHandler, Slot, Buffer, Offset, Length);
|
||
|
Len += Length;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Len;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
HalpSetPCIData (
|
||
|
IN ULONG BusNumber,
|
||
|
IN PCI_SLOT_NUMBER Slot,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset,
|
||
|
IN ULONG Length
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
The function returns the Pci bus data for a device.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word)
|
||
|
|
||
|
Buffer - Supplies the space to store the data.
|
||
|
|
||
|
Length - Supplies a count in bytes of the maximum amount to return.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns the amount of data stored into the buffer.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PBUSHANDLER BusHandler;
|
||
|
PPCI_COMMON_CONFIG PciData, PciData2;
|
||
|
UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
|
||
|
UCHAR iBuffer2[PCI_COMMON_HDR_LENGTH];
|
||
|
PPCIPBUSDATA BusData;
|
||
|
ULONG Len;
|
||
|
|
||
|
BusHandler = HalpGetPciBusHandler (BusNumber);
|
||
|
if (!BusHandler) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (Length > sizeof (PCI_COMMON_CONFIG)) {
|
||
|
Length = sizeof (PCI_COMMON_CONFIG);
|
||
|
}
|
||
|
|
||
|
Len = 0;
|
||
|
PciData = (PPCI_COMMON_CONFIG) iBuffer;
|
||
|
PciData2 = (PPCI_COMMON_CONFIG) iBuffer2;
|
||
|
|
||
|
if (Offset >= PCI_COMMON_HDR_LENGTH) {
|
||
|
//
|
||
|
// The user did not request any data from the common
|
||
|
// header. Verify the PCI device exists, then continue in
|
||
|
// the device specific area.
|
||
|
//
|
||
|
|
||
|
HalpReadPCIConfig (BusHandler, Slot, PciData, 0, sizeof(ULONG));
|
||
|
|
||
|
if (PciData->VendorID == PCI_INVALID_VENDORID) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Caller requested to set at least some data within the
|
||
|
// common header.
|
||
|
//
|
||
|
|
||
|
Len = PCI_COMMON_HDR_LENGTH;
|
||
|
HalpReadPCIConfig (BusHandler, Slot, PciData, 0, Len);
|
||
|
if (PciData->VendorID == PCI_INVALID_VENDORID ||
|
||
|
PCI_CONFIG_TYPE (PciData) != 0) {
|
||
|
|
||
|
// no device, or header type unkown
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set this device as configured
|
||
|
//
|
||
|
|
||
|
BusData = (PPCIPBUSDATA) BusHandler->BusData;
|
||
|
//
|
||
|
// Copy COMMON_HDR values to buffer2, then overlay callers changes.
|
||
|
//
|
||
|
|
||
|
RtlMoveMemory (iBuffer2, iBuffer, Len);
|
||
|
|
||
|
Len -= Offset;
|
||
|
if (Len > Length) {
|
||
|
Len = Length;
|
||
|
}
|
||
|
|
||
|
RtlMoveMemory (iBuffer2+Offset, Buffer, Len);
|
||
|
|
||
|
// in case interrupt line or pin was editted
|
||
|
HalpPCILine2Pin (BusHandler, RootHandler, Slot, PciData2, PciData);
|
||
|
|
||
|
//
|
||
|
// Set new PCI configuration
|
||
|
//
|
||
|
|
||
|
HalpWritePCIConfig (BusHandler, Slot, iBuffer2+Offset, Offset, Len);
|
||
|
|
||
|
Offset += Len;
|
||
|
Buffer += Len;
|
||
|
Length -= Len;
|
||
|
}
|
||
|
|
||
|
if (Length) {
|
||
|
if (Offset >= PCI_COMMON_HDR_LENGTH) {
|
||
|
//
|
||
|
// The remaining Buffer comes from the Device Specific
|
||
|
// area - put on the kitten gloves and write it
|
||
|
//
|
||
|
// Specific read/writes to the PCI device specific area
|
||
|
// are guarenteed:
|
||
|
//
|
||
|
// Not to read/write any byte outside the area specified
|
||
|
// by the caller. (this may cause WORD or BYTE references
|
||
|
// to the area in order to read the non-dword aligned
|
||
|
// ends of the request)
|
||
|
//
|
||
|
// To use a WORD access if the requested length is exactly
|
||
|
// a WORD long & WORD aligned.
|
||
|
//
|
||
|
// To use a BYTE access if the requested length is exactly
|
||
|
// a BYTE long.
|
||
|
//
|
||
|
|
||
|
HalpWritePCIConfig (BusHandler, Slot, Buffer, Offset, Length);
|
||
|
Len += Length;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Len;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HalpReadPCIConfig (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN PCI_SLOT_NUMBER Slot,
|
||
|
IN PVOID Buffer,
|
||
|
IN ULONG Offset,
|
||
|
IN ULONG Length
|
||
|
)
|
||
|
{
|
||
|
if (!HalpValidPCISlot (BusHandler, Slot)) {
|
||
|
//
|
||
|
// Invalid SlotID return no data
|
||
|
//
|
||
|
|
||
|
RtlFillMemory (Buffer, Length, (UCHAR) -1);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length,
|
||
|
PCIConfigHandlers.ConfigRead);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HalpWritePCIConfig (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN PCI_SLOT_NUMBER Slot,
|
||
|
IN PVOID Buffer,
|
||
|
IN ULONG Offset,
|
||
|
IN ULONG Length
|
||
|
)
|
||
|
{
|
||
|
if (!HalpValidPCISlot (BusHandler, Slot)) {
|
||
|
//
|
||
|
// Invalid SlotID do nothing
|
||
|
//
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length,
|
||
|
PCIConfigHandlers.ConfigWrite);
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
HalpValidPCISlot (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN PCI_SLOT_NUMBER Slot
|
||
|
)
|
||
|
{
|
||
|
PCI_SLOT_NUMBER Slot2;
|
||
|
UCHAR HeaderType;
|
||
|
ULONG i;
|
||
|
|
||
|
if (Slot.u.bits.Reserved != 0) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (Slot.u.bits.DeviceNumber >= PCIMaxDevice) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (Slot.u.bits.FunctionNumber == 0) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Non zero function numbers are only supported if the
|
||
|
// device has the PCI_MULTIFUNCTION bit set in it's header
|
||
|
//
|
||
|
|
||
|
i = Slot.u.bits.DeviceNumber;
|
||
|
|
||
|
//
|
||
|
// Read DeviceNumber, Function zero, to determine if the
|
||
|
// PCI supports multifunction devices
|
||
|
//
|
||
|
|
||
|
Slot2 = Slot;
|
||
|
Slot2.u.bits.FunctionNumber = 0;
|
||
|
|
||
|
HalpReadPCIConfig (
|
||
|
BusHandler,
|
||
|
Slot2,
|
||
|
&HeaderType,
|
||
|
FIELD_OFFSET (PCI_COMMON_CONFIG, HeaderType),
|
||
|
sizeof (UCHAR)
|
||
|
);
|
||
|
|
||
|
if (!(HeaderType & PCI_MULTIFUNCTION) || HeaderType == 0xFF) {
|
||
|
// this device doesn't exists or doesn't support MULTIFUNCTION types
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
HalpPCIConfig (
|
||
|
IN PBUSHANDLER 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];
|
||
|
PPCIPBUSDATA BusData;
|
||
|
|
||
|
BusData = (PPCIPBUSDATA) BusHandler->BusData;
|
||
|
PCIConfigHandlers.Synchronize (BusHandler, Slot, &OldIrql, State);
|
||
|
|
||
|
while (Length) {
|
||
|
i = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)];
|
||
|
i = ConfigIO[i] (BusData, State, Buffer, Offset);
|
||
|
|
||
|
Offset += i;
|
||
|
Buffer += i;
|
||
|
Length -= i;
|
||
|
}
|
||
|
|
||
|
PCIConfigHandlers.ReleaseSynchronzation (BusHandler, OldIrql);
|
||
|
}
|
||
|
|
||
|
VOID HalpPCISynchronizeType1 (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN PCI_SLOT_NUMBER Slot,
|
||
|
IN PKIRQL Irql,
|
||
|
IN PPCI_TYPE1_CFG_BITS PciCfg1
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// Initialize PciCfg1
|
||
|
//
|
||
|
|
||
|
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;
|
||
|
|
||
|
//
|
||
|
// Synchronize with PCI type1 config space
|
||
|
//
|
||
|
|
||
|
//KeAcquireSpinLock (&HalpPCIConfigLock, Irql);
|
||
|
}
|
||
|
|
||
|
VOID HalpPCIReleaseSynchronzationType1 (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN KIRQL Irql
|
||
|
)
|
||
|
{
|
||
|
PCI_TYPE1_CFG_BITS PciCfg1;
|
||
|
PPCIPBUSDATA BusData;
|
||
|
|
||
|
//
|
||
|
// Disable PCI configuration space
|
||
|
//
|
||
|
|
||
|
PciCfg1.u.AsULONG = 0;
|
||
|
BusData = (PPCIPBUSDATA) BusHandler->BusData;
|
||
|
WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1.u.AsULONG);
|
||
|
|
||
|
//
|
||
|
// Release spinlock
|
||
|
//
|
||
|
|
||
|
//KeReleaseSpinLock (&HalpPCIConfigLock, Irql);
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
HalpPCIReadUcharType1 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PPCI_TYPE1_CFG_BITS PciCfg1,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
)
|
||
|
{
|
||
|
ULONG i;
|
||
|
|
||
|
i = Offset % sizeof(ULONG);
|
||
|
PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
|
||
|
WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
|
||
|
*Buffer = READ_PORT_UCHAR ((PUCHAR) (BusData->Config.Type1.Data + i));
|
||
|
return sizeof (UCHAR);
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
HalpPCIReadUshortType1 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PPCI_TYPE1_CFG_BITS PciCfg1,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
)
|
||
|
{
|
||
|
ULONG i;
|
||
|
|
||
|
i = Offset % sizeof(ULONG);
|
||
|
PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
|
||
|
WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
|
||
|
*((PUSHORT) Buffer) = READ_PORT_USHORT ((PUSHORT) (BusData->Config.Type1.Data + i));
|
||
|
return sizeof (USHORT);
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
HalpPCIReadUlongType1 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PPCI_TYPE1_CFG_BITS PciCfg1,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
)
|
||
|
{
|
||
|
PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
|
||
|
WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
|
||
|
*((PULONG) Buffer) = READ_PORT_ULONG ((PULONG) BusData->Config.Type1.Data);
|
||
|
return sizeof (ULONG);
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
HalpPCIWriteUcharType1 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PPCI_TYPE1_CFG_BITS PciCfg1,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
)
|
||
|
{
|
||
|
ULONG i;
|
||
|
|
||
|
i = Offset % sizeof(ULONG);
|
||
|
PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
|
||
|
WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
|
||
|
WRITE_PORT_UCHAR ((PUCHAR) (BusData->Config.Type1.Data + i), *Buffer);
|
||
|
return sizeof (UCHAR);
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
HalpPCIWriteUshortType1 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PPCI_TYPE1_CFG_BITS PciCfg1,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
)
|
||
|
{
|
||
|
ULONG i;
|
||
|
|
||
|
i = Offset % sizeof(ULONG);
|
||
|
PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
|
||
|
WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
|
||
|
WRITE_PORT_USHORT ((PUSHORT) (BusData->Config.Type1.Data + i), *((PUSHORT) Buffer));
|
||
|
return sizeof (USHORT);
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
HalpPCIWriteUlongType1 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PPCI_TYPE1_CFG_BITS PciCfg1,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
)
|
||
|
{
|
||
|
PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
|
||
|
WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
|
||
|
WRITE_PORT_ULONG ((PULONG) BusData->Config.Type1.Data, *((PULONG) Buffer));
|
||
|
return sizeof (ULONG);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID HalpPCISynchronizeType2 (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN PCI_SLOT_NUMBER Slot,
|
||
|
IN PKIRQL Irql,
|
||
|
IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr
|
||
|
)
|
||
|
{
|
||
|
PCI_TYPE2_CSE_BITS PciCfg2Cse;
|
||
|
PPCIPBUSDATA BusData;
|
||
|
|
||
|
BusData = (PPCIPBUSDATA) BusHandler->BusData;
|
||
|
|
||
|
//
|
||
|
// Initialize Cfg2Addr
|
||
|
//
|
||
|
|
||
|
PciCfg2Addr->u.AsUSHORT = 0;
|
||
|
PciCfg2Addr->u.bits.Agent = (USHORT) Slot.u.bits.DeviceNumber;
|
||
|
PciCfg2Addr->u.bits.AddressBase = (USHORT) BusData->Config.Type2.Base;
|
||
|
|
||
|
//
|
||
|
// Synchronize with type2 config space - type2 config space
|
||
|
// remaps 4K of IO space, so we can not allow other I/Os to occur
|
||
|
// while using type2 config space, hence the disable_interrupts.
|
||
|
//
|
||
|
|
||
|
//KeAcquireSpinLock (&HalpPCIConfigLock, Irql);
|
||
|
//DISABLE_INTERRUPTS (); // is not MP safe
|
||
|
|
||
|
PciCfg2Cse.u.AsUCHAR = 0;
|
||
|
PciCfg2Cse.u.bits.Enable = TRUE;
|
||
|
PciCfg2Cse.u.bits.FunctionNumber = (UCHAR) Slot.u.bits.FunctionNumber;
|
||
|
PciCfg2Cse.u.bits.Key = 0xff;
|
||
|
|
||
|
//
|
||
|
// Select bus & enable type 2 configuration space
|
||
|
//
|
||
|
|
||
|
WRITE_PORT_UCHAR (BusData->Config.Type2.Forward, (UCHAR) BusHandler->BusNumber);
|
||
|
WRITE_PORT_UCHAR (BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID HalpPCIReleaseSynchronzationType2 (
|
||
|
IN PBUSHANDLER BusHandler,
|
||
|
IN KIRQL Irql
|
||
|
)
|
||
|
{
|
||
|
PCI_TYPE2_CSE_BITS PciCfg2Cse;
|
||
|
PPCIPBUSDATA BusData;
|
||
|
|
||
|
//
|
||
|
// disable PCI configuration space
|
||
|
//
|
||
|
|
||
|
BusData = (PPCIPBUSDATA) BusHandler->BusData;
|
||
|
|
||
|
PciCfg2Cse.u.AsUCHAR = 0;
|
||
|
WRITE_PORT_UCHAR (BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
|
||
|
|
||
|
//
|
||
|
// Restore interrupts, release spinlock
|
||
|
//
|
||
|
|
||
|
//ENABLE_INTERRUPTS ();
|
||
|
//KeReleaseSpinLock (&HalpPCIConfigLock, Irql);
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
HalpPCIReadUcharType2 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
)
|
||
|
{
|
||
|
PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
|
||
|
*Buffer = READ_PORT_UCHAR ((PUCHAR) PciCfg2Addr->u.AsUSHORT);
|
||
|
return sizeof (UCHAR);
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
HalpPCIReadUshortType2 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
)
|
||
|
{
|
||
|
PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
|
||
|
*((PUSHORT) Buffer) = READ_PORT_USHORT ((PUSHORT) PciCfg2Addr->u.AsUSHORT);
|
||
|
return sizeof (USHORT);
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
HalpPCIReadUlongType2 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
)
|
||
|
{
|
||
|
PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
|
||
|
*((PULONG) Buffer) = READ_PORT_ULONG ((PULONG) PciCfg2Addr->u.AsUSHORT);
|
||
|
return sizeof(ULONG);
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
HalpPCIWriteUcharType2 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
)
|
||
|
{
|
||
|
PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
|
||
|
WRITE_PORT_UCHAR ((PUCHAR) PciCfg2Addr->u.AsUSHORT, *Buffer);
|
||
|
return sizeof (UCHAR);
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
HalpPCIWriteUshortType2 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
)
|
||
|
{
|
||
|
PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
|
||
|
WRITE_PORT_USHORT ((PUSHORT) PciCfg2Addr->u.AsUSHORT, *((PUSHORT) Buffer));
|
||
|
return sizeof (USHORT);
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
HalpPCIWriteUlongType2 (
|
||
|
IN PPCIPBUSDATA BusData,
|
||
|
IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
|
||
|
IN PUCHAR Buffer,
|
||
|
IN ULONG Offset
|
||
|
)
|
||
|
{
|
||
|
PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
|
||
|
WRITE_PORT_ULONG ((PULONG) PciCfg2Addr->u.AsUSHORT, *((PULONG) Buffer));
|
||
|
return sizeof(ULONG);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpAssignPCISlotResources (
|
||
|
IN ULONG BusNumber,
|
||
|
IN ULONG Slot,
|
||
|
IN OUT PCM_RESOURCE_LIST *pAllocatedResources
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Reads the targeted device to determine it's required resources.
|
||
|
Calls IoAssignResources to allocate them.
|
||
|
Sets the targeted device with it's assigned resoruces
|
||
|
and returns the assignments to the caller.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
STATUS_SUCCESS or error
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PBUSHANDLER BusHandler;
|
||
|
UCHAR buffer[PCI_COMMON_HDR_LENGTH];
|
||
|
UCHAR buffer2[PCI_COMMON_HDR_LENGTH];
|
||
|
PPCI_COMMON_CONFIG PciData, PciData2;
|
||
|
PCI_SLOT_NUMBER PciSlot;
|
||
|
ULONG i, j, length, type;
|
||
|
PHYSICAL_ADDRESS Address;
|
||
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor;
|
||
|
static PCM_RESOURCE_LIST CmResList;
|
||
|
USHORT NewCommand;
|
||
|
|
||
|
BusHandler = HalpGetPciBusHandler (BusNumber);
|
||
|
if (!BusHandler) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
*pAllocatedResources = NULL;
|
||
|
|
||
|
PciData = (PPCI_COMMON_CONFIG) buffer;
|
||
|
PciData2 = (PPCI_COMMON_CONFIG) buffer2;
|
||
|
PciSlot = *((PPCI_SLOT_NUMBER) &Slot);
|
||
|
BusNumber = BusHandler->BusNumber;
|
||
|
|
||
|
//
|
||
|
// Read the PCI device's configuration
|
||
|
//
|
||
|
|
||
|
HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
|
||
|
if (PciData->VendorID == PCI_INVALID_VENDORID) {
|
||
|
return STATUS_NO_SUCH_DEVICE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make a copy of the device's current settings
|
||
|
//
|
||
|
|
||
|
RtlMoveMemory (buffer2, buffer, PCI_COMMON_HDR_LENGTH);
|
||
|
|
||
|
//
|
||
|
// Set resources to all bits on to see what type of resources
|
||
|
// are required.
|
||
|
//
|
||
|
|
||
|
for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
|
||
|
PciData->u.type0.BaseAddresses[j] = 0xFFFFFFFF;
|
||
|
}
|
||
|
PciData->u.type0.ROMBaseAddress = 0xFFFFFFFF;
|
||
|
|
||
|
NewCommand = PciData->Command;
|
||
|
PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE);
|
||
|
PciData->u.type0.ROMBaseAddress &= ~PCI_ROMADDRESS_ENABLED;
|
||
|
HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
|
||
|
HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
|
||
|
HalpPCIPin2Line (BusHandler, RootHandler, PciSlot, PciData);
|
||
|
|
||
|
//
|
||
|
// Restore the device's settings in case we don't complete
|
||
|
//
|
||
|
|
||
|
HalpWritePCIConfig (BusHandler, PciSlot, buffer2, 0, PCI_COMMON_HDR_LENGTH);
|
||
|
|
||
|
//
|
||
|
// Build a CmResource descriptor list for the device
|
||
|
//
|
||
|
|
||
|
if (!CmResList) {
|
||
|
// NtLdr pool is only allocated and never freed. Allocate the
|
||
|
// buffer once, and from then on just use the buffer over
|
||
|
|
||
|
CmResList = ExAllocatePool (PagedPool,
|
||
|
sizeof (CM_RESOURCE_LIST) +
|
||
|
sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (!CmResList) {
|
||
|
return STATUS_NO_MEMORY;
|
||
|
}
|
||
|
|
||
|
RtlZeroMemory (CmResList,
|
||
|
sizeof (CM_RESOURCE_LIST) +
|
||
|
sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2)
|
||
|
);
|
||
|
|
||
|
*pAllocatedResources = CmResList;
|
||
|
CmResList->List[0].InterfaceType = PCIBus;
|
||
|
CmResList->List[0].BusNumber = BusNumber;
|
||
|
|
||
|
CmDescriptor = CmResList->List[0].PartialResourceList.PartialDescriptors;
|
||
|
if (PciData->u.type0.InterruptPin) {
|
||
|
|
||
|
CmDescriptor->Type = CmResourceTypeInterrupt;
|
||
|
CmDescriptor->ShareDisposition = CmResourceShareShared;
|
||
|
CmDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
|
||
|
|
||
|
// in the loader interrupts aren't actually enabled, so just
|
||
|
// pass back the untranslated values
|
||
|
CmDescriptor->u.Interrupt.Level = PciData->u.type0.InterruptLine;
|
||
|
CmDescriptor->u.Interrupt.Vector = PciData->u.type0.InterruptLine;
|
||
|
CmDescriptor->u.Interrupt.Affinity = 1;
|
||
|
|
||
|
CmResList->List[0].PartialResourceList.Count++;
|
||
|
CmDescriptor++;
|
||
|
}
|
||
|
|
||
|
// clear last address index + 1
|
||
|
PciData->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES] = 0;
|
||
|
if (PciData2->u.type0.ROMBaseAddress & PCI_ROMADDRESS_ENABLED) {
|
||
|
|
||
|
// put rom address in last index+1
|
||
|
PciData->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES] =
|
||
|
PciData->u.type0.ROMBaseAddress & ~PCI_ADDRESS_IO_SPACE;
|
||
|
|
||
|
PciData2->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES] =
|
||
|
PciData2->u.type0.ROMBaseAddress & ~PCI_ADDRESS_IO_SPACE;
|
||
|
}
|
||
|
|
||
|
for (j=0; j < PCI_TYPE0_ADDRESSES + 1; j++) {
|
||
|
if (PciData->u.type0.BaseAddresses[j]) {
|
||
|
i = PciData->u.type0.BaseAddresses[j];
|
||
|
|
||
|
//
|
||
|
// Make sure the appropriate decode is turned on for this BAR.
|
||
|
//
|
||
|
if (i & PCI_ADDRESS_IO_SPACE) {
|
||
|
NewCommand |= PCI_ENABLE_IO_SPACE;
|
||
|
} else {
|
||
|
NewCommand |= PCI_ENABLE_MEMORY_SPACE;
|
||
|
}
|
||
|
|
||
|
// scan for first set bit, that's the length & alignment
|
||
|
length = 1 << (i & PCI_ADDRESS_IO_SPACE ? 2 : 4);
|
||
|
Address.HighPart = 0;
|
||
|
Address.LowPart = PciData2->u.type0.BaseAddresses[j] & ~(length-1);
|
||
|
while (!(i & length) && length) {
|
||
|
length <<= 1;
|
||
|
}
|
||
|
|
||
|
// translate bus specific address
|
||
|
type = (i & PCI_ADDRESS_IO_SPACE) ? 0 : 1;
|
||
|
if (!HalTranslateBusAddress (
|
||
|
PCIBus,
|
||
|
BusNumber,
|
||
|
Address,
|
||
|
&type,
|
||
|
&Address )) {
|
||
|
// translation failed, skip it
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// fill in CmDescriptor to return
|
||
|
if (type == 0) {
|
||
|
CmDescriptor->Type = CmResourceTypePort;
|
||
|
CmDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
|
||
|
CmDescriptor->Flags = CM_RESOURCE_PORT_IO;
|
||
|
CmDescriptor->u.Port.Length = length;
|
||
|
CmDescriptor->u.Port.Start = Address;
|
||
|
} else {
|
||
|
CmDescriptor->Type = CmResourceTypeMemory;
|
||
|
CmDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
|
||
|
CmDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
|
||
|
CmDescriptor->u.Memory.Length = length;
|
||
|
CmDescriptor->u.Memory.Start = Address;
|
||
|
|
||
|
if (j == PCI_TYPE0_ADDRESSES) {
|
||
|
// this is a ROM address
|
||
|
CmDescriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CmResList->List[0].PartialResourceList.Count++;
|
||
|
CmDescriptor++;
|
||
|
|
||
|
if (i & PCI_TYPE_64BIT) {
|
||
|
// skip upper half of 64 bit address.
|
||
|
j++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If any decodes need to be turned on, do this now.
|
||
|
//
|
||
|
if (NewCommand != PciData2->Command) {
|
||
|
HalpWritePCIConfig(BusHandler,
|
||
|
PciSlot,
|
||
|
&NewCommand,
|
||
|
FIELD_OFFSET(PCI_COMMON_CONFIG, Command),
|
||
|
sizeof(NewCommand));
|
||
|
}
|
||
|
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|