554 lines
12 KiB
C
554 lines
12 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ixbusdat.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the IoXxx routines for the NT I/O system that
|
||
are hardware dependent. Were these routines not hardware dependent,
|
||
they would reside in the iosubs.c module.
|
||
|
||
Author:
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
#include "bootia64.h"
|
||
#include "arc.h"
|
||
#include "ixfwhal.h"
|
||
#if defined(NEC_98)
|
||
#include "nec98.h"
|
||
#else //NEC_98
|
||
#include "eisa.h"
|
||
#endif //NEC_98
|
||
#include "mca.h"
|
||
#include "ntconfig.h"
|
||
|
||
#if defined(NEC_98)
|
||
#else
|
||
ULONG
|
||
HalpGetCmosData(
|
||
IN ULONG BusNumber,
|
||
IN ULONG SlotNumber,
|
||
IN PVOID Buffer,
|
||
IN ULONG Length
|
||
);
|
||
|
||
ULONG
|
||
HalpGetPosData(
|
||
IN ULONG BusNumber,
|
||
IN ULONG SlotNumber,
|
||
IN PVOID Buffer,
|
||
IN ULONG Offset,
|
||
IN ULONG Length
|
||
);
|
||
|
||
ULONG
|
||
HalpGetEisaData(
|
||
IN ULONG BusNumber,
|
||
IN ULONG SlotNumber,
|
||
IN PVOID Buffer,
|
||
IN ULONG Offset,
|
||
IN ULONG Length
|
||
);
|
||
#endif //!NEC_98
|
||
|
||
ULONG
|
||
HalpGetPCIData(
|
||
IN ULONG BusNumber,
|
||
IN ULONG SlotNumber,
|
||
IN PVOID Buffer,
|
||
IN ULONG Offset,
|
||
IN ULONG Length
|
||
);
|
||
|
||
ULONG
|
||
HalpSetPCIData(
|
||
IN ULONG BusNumber,
|
||
IN ULONG SlotNumber,
|
||
IN PVOID Buffer,
|
||
IN ULONG Offset,
|
||
IN ULONG Length
|
||
);
|
||
|
||
NTSTATUS
|
||
HalpAssignPCISlotResources (
|
||
IN ULONG BusNumber,
|
||
IN ULONG Slot,
|
||
IN OUT PCM_RESOURCE_LIST *AllocatedResources
|
||
);
|
||
|
||
/*
|
||
*
|
||
* Router functions. Routes each call to specific handler
|
||
*
|
||
*/
|
||
|
||
|
||
ULONG
|
||
HalGetBusData(
|
||
IN BUS_DATA_TYPE BusDataType,
|
||
IN ULONG BusNumber,
|
||
IN ULONG SlotNumber,
|
||
IN PVOID Buffer,
|
||
IN ULONG Length
|
||
)
|
||
{
|
||
return HalGetBusDataByOffset (BusDataType,BusNumber,SlotNumber,Buffer,0,Length);
|
||
}
|
||
|
||
ULONG
|
||
HalGetBusDataByOffset (
|
||
IN BUS_DATA_TYPE BusDataType,
|
||
IN ULONG BusNumber,
|
||
IN ULONG Slot,
|
||
IN PVOID Buffer,
|
||
IN ULONG Offset,
|
||
IN ULONG Length
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Dispatcher for GetBusData
|
||
|
||
--*/
|
||
{
|
||
switch (BusDataType) {
|
||
#if defined(NEC_98)
|
||
#else
|
||
case Cmos:
|
||
if (Offset != 0) {
|
||
return 0;
|
||
}
|
||
|
||
return HalpGetCmosData(BusNumber, Slot, Buffer, Length);
|
||
|
||
case Pos:
|
||
return HalpGetPosData(BusNumber, Slot, Buffer, Offset, Length);
|
||
|
||
case EisaConfiguration:
|
||
return HalpGetEisaData(BusNumber, Slot, Buffer, Offset, Length);
|
||
#endif //NEC_98
|
||
|
||
case PCIConfiguration:
|
||
return HalpGetPCIData(BusNumber, Slot, Buffer, Offset, Length);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
ULONG
|
||
HalSetBusData(
|
||
IN BUS_DATA_TYPE BusDataType,
|
||
IN ULONG BusNumber,
|
||
IN ULONG SlotNumber,
|
||
IN PVOID Buffer,
|
||
IN ULONG Length
|
||
)
|
||
{
|
||
return HalSetBusDataByOffset (BusDataType,BusNumber,SlotNumber,Buffer,0,Length);
|
||
}
|
||
|
||
ULONG
|
||
HalSetBusDataByOffset(
|
||
IN BUS_DATA_TYPE BusDataType,
|
||
IN ULONG BusNumber,
|
||
IN ULONG Slot,
|
||
IN PVOID Buffer,
|
||
IN ULONG Offset,
|
||
IN ULONG Length
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Dispatcher for SetBusData
|
||
|
||
--*/
|
||
{
|
||
switch (BusDataType) {
|
||
case PCIConfiguration:
|
||
return HalpSetPCIData(BusNumber, Slot, Buffer, Offset, Length);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
HalAssignSlotResources (
|
||
IN PUNICODE_STRING RegistryPath,
|
||
IN PUNICODE_STRING DriverClassName OPTIONAL,
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
||
IN INTERFACE_TYPE BusType,
|
||
IN ULONG BusNumber,
|
||
IN ULONG SlotNumber,
|
||
IN OUT PCM_RESOURCE_LIST *AllocatedResources
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Dispatcher for AssignSlotResources
|
||
|
||
--*/
|
||
{
|
||
switch (BusType) {
|
||
case PCIBus:
|
||
return HalpAssignPCISlotResources (
|
||
BusNumber,
|
||
SlotNumber,
|
||
AllocatedResources
|
||
);
|
||
default:
|
||
break;
|
||
}
|
||
return STATUS_NOT_FOUND;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/**
|
||
**
|
||
** Standard PC bus functions
|
||
**
|
||
**/
|
||
|
||
|
||
|
||
BOOLEAN
|
||
HalTranslateBusAddress(
|
||
IN INTERFACE_TYPE InterfaceType,
|
||
IN ULONG BusNumber,
|
||
IN PHYSICAL_ADDRESS BusAddress,
|
||
IN OUT PULONG AddressSpace,
|
||
OUT PPHYSICAL_ADDRESS TranslatedAddress
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function translates a bus-relative address space and address into
|
||
a system physical address.
|
||
|
||
Arguments:
|
||
|
||
BusNumber - Supplies the bus number. This is ignored on
|
||
standard x86 systems
|
||
|
||
BusAddress - Supplies the bus-relative address
|
||
|
||
AddressSpace - Supplies the address space number.
|
||
Returns the host address space number.
|
||
|
||
AddressSpace == 0 => I/O space
|
||
AddressSpace == 1 => memory space
|
||
|
||
TranslatedAddress - Pointer to a physical_address.
|
||
|
||
Return Value:
|
||
|
||
System physical address corresponding to the supplied bus relative
|
||
address and bus address number.
|
||
|
||
--*/
|
||
|
||
{
|
||
TranslatedAddress->HighPart = 0;
|
||
TranslatedAddress->LowPart = BusAddress.LowPart;
|
||
return(TRUE);
|
||
}
|
||
|
||
#if defined(NEC_98)
|
||
#else
|
||
ULONG
|
||
HalpGetPosData (
|
||
IN ULONG BusNumber,
|
||
IN ULONG SlotNumber,
|
||
IN PVOID Buffer,
|
||
IN ULONG DOffset,
|
||
IN ULONG Length
|
||
)
|
||
/*--
|
||
|
||
Arguments:
|
||
|
||
BusDataType - Supplies the type of bus.
|
||
|
||
BusNumber - Indicates which bus.
|
||
|
||
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.
|
||
|
||
--*/
|
||
{
|
||
PVOID McaRegisterBase = 0;
|
||
ULONG Index = 0;
|
||
PUCHAR DataBuffer = Buffer;
|
||
ULONG DataLength = 0;
|
||
PUCHAR PosBase;
|
||
ULONG Offset;
|
||
|
||
if (DOffset != 0 || MachineType != MACHINE_TYPE_MCA) {
|
||
return 0;
|
||
}
|
||
|
||
PosBase = (PUCHAR) &((PMCA_CONTROL) McaRegisterBase)->Pos;
|
||
|
||
//
|
||
// Place the specified adapter into setup mode.
|
||
//
|
||
|
||
WRITE_PORT_UCHAR((PVOID) &((PMCA_CONTROL) McaRegisterBase)->AdapterSetup,
|
||
(UCHAR) ( MCA_ADAPTER_SETUP_ON | SlotNumber ));
|
||
|
||
while (DataLength < Length && DataLength < 6) {
|
||
DataBuffer[DataLength] = READ_PORT_UCHAR( PosBase + DataLength );
|
||
DataLength++;
|
||
}
|
||
|
||
while (DataLength < Length) {
|
||
|
||
WRITE_PORT_UCHAR((PVOID) &((PPROGRAMMABLE_OPTION_SELECT)
|
||
PosBase)->SubaddressExtensionLsb, (UCHAR) Index);
|
||
|
||
WRITE_PORT_UCHAR((PVOID) &((PPROGRAMMABLE_OPTION_SELECT)
|
||
PosBase)->SubaddressExtensionMsb, (UCHAR) (Index >> 8));
|
||
|
||
DataBuffer[Index + 6] = READ_PORT_UCHAR(
|
||
(PVOID) &((PPROGRAMMABLE_OPTION_SELECT)PosBase)->OptionSelectData2);
|
||
|
||
DataLength++;
|
||
|
||
if (DataLength < Length) {
|
||
Offset = DataLength + ((Length - DataLength) / 2);
|
||
DataBuffer[Offset] = READ_PORT_UCHAR(
|
||
(PVOID) &((PPROGRAMMABLE_OPTION_SELECT)PosBase)->OptionSelectData3);
|
||
DataLength++;
|
||
Index++;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Disable adapter setup.
|
||
//
|
||
|
||
WRITE_PORT_UCHAR((PVOID) &((PMCA_CONTROL) McaRegisterBase)->AdapterSetup,
|
||
(UCHAR) ( MCA_ADAPTER_SETUP_OFF ));
|
||
return 1;
|
||
}
|
||
|
||
ULONG
|
||
HalpGetEisaData (
|
||
IN ULONG BusNumber,
|
||
IN ULONG SlotNumber,
|
||
IN PVOID Buffer,
|
||
IN ULONG Offset,
|
||
IN ULONG Length
|
||
)
|
||
/*--
|
||
|
||
Arguments:
|
||
|
||
BusDataType - Supplies the type of bus.
|
||
|
||
BusNumber - Indicates which bus.
|
||
|
||
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.
|
||
|
||
--*/
|
||
{
|
||
|
||
ULONG DataLength = 0;
|
||
ULONG i;
|
||
ULONG TotalDataSize;
|
||
ULONG SlotDataSize;
|
||
ULONG PartialCount;
|
||
ULONG Index = 0;
|
||
PUCHAR DataBuffer = Buffer;
|
||
PCONFIGURATION_COMPONENT_DATA ConfigData;
|
||
PCM_EISA_SLOT_INFORMATION SlotInformation;
|
||
PCM_PARTIAL_RESOURCE_LIST Descriptor;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResource;
|
||
BOOLEAN Found = FALSE;
|
||
|
||
if (MachineType != MACHINE_TYPE_EISA) {
|
||
return 0;
|
||
}
|
||
|
||
ConfigData = KeFindConfigurationEntry(
|
||
FwConfigurationTree,
|
||
AdapterClass,
|
||
EisaAdapter,
|
||
NULL
|
||
);
|
||
|
||
if (ConfigData == NULL) {
|
||
#if defined(ENABLE_LOADER_EBUG)
|
||
DbgPrint("HalGetBusData: KeFindConfigurationEntry failed\n");
|
||
#endif
|
||
return(0);
|
||
}
|
||
|
||
Descriptor = ConfigData->ConfigurationData;
|
||
PartialResource = Descriptor->PartialDescriptors;
|
||
PartialCount = Descriptor->Count;
|
||
|
||
for (i = 0; i < PartialCount; i++) {
|
||
|
||
//
|
||
// Do each partial Resource
|
||
//
|
||
|
||
switch (PartialResource->Type) {
|
||
case CmResourceTypeNull:
|
||
case CmResourceTypePort:
|
||
case CmResourceTypeInterrupt:
|
||
case CmResourceTypeMemory:
|
||
case CmResourceTypeDma:
|
||
|
||
//
|
||
// We dont care about these.
|
||
//
|
||
|
||
PartialResource++;
|
||
|
||
break;
|
||
|
||
case CmResourceTypeDeviceSpecific:
|
||
|
||
//
|
||
// Bingo!
|
||
//
|
||
|
||
TotalDataSize = PartialResource->u.DeviceSpecificData.DataSize;
|
||
|
||
SlotInformation = (PCM_EISA_SLOT_INFORMATION)
|
||
((PUCHAR)PartialResource +
|
||
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
||
|
||
while (((LONG)TotalDataSize) > 0) {
|
||
|
||
if (SlotInformation->ReturnCode == EISA_EMPTY_SLOT) {
|
||
|
||
SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION);
|
||
|
||
} else {
|
||
|
||
SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION) +
|
||
SlotInformation->NumberFunctions *
|
||
sizeof(CM_EISA_FUNCTION_INFORMATION);
|
||
}
|
||
|
||
if (SlotDataSize > TotalDataSize) {
|
||
|
||
//
|
||
// Something is wrong again
|
||
//
|
||
|
||
#if defined(ENABLE_LOADER_EBUG)
|
||
DbgPrint("HalGetBusData: SlotDataSize > TotalDataSize\n");
|
||
#endif
|
||
|
||
return(0);
|
||
|
||
}
|
||
|
||
if (SlotNumber != 0) {
|
||
|
||
SlotNumber--;
|
||
|
||
SlotInformation = (PCM_EISA_SLOT_INFORMATION)
|
||
((PUCHAR)SlotInformation + SlotDataSize);
|
||
|
||
TotalDataSize -= SlotDataSize;
|
||
|
||
continue;
|
||
|
||
}
|
||
|
||
//
|
||
// This is our slot
|
||
//
|
||
|
||
Found = TRUE;
|
||
break;
|
||
|
||
}
|
||
|
||
//
|
||
// End loop
|
||
//
|
||
|
||
i = PartialCount;
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
#if defined(ENABLE_LOADER_EBUG)
|
||
DbgPrint("Bad Data in registry!\n");
|
||
#endif
|
||
|
||
return(0);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (Found) {
|
||
|
||
//
|
||
// As a hack if the length is zero then the buffer points to a
|
||
// PVOID where the pointer to the data should be stored. This is
|
||
// done in the loader because we quickly run out of heap scaning
|
||
// all of the EISA configuration data.
|
||
//
|
||
|
||
if (Length == 0) {
|
||
|
||
//
|
||
// Return the pointer to the mini-port driver.
|
||
//
|
||
|
||
*((PVOID *)Buffer) = SlotInformation;
|
||
return(SlotDataSize);
|
||
}
|
||
|
||
i = Length + Offset;
|
||
if (i > SlotDataSize) {
|
||
i = SlotDataSize;
|
||
}
|
||
|
||
DataLength = i - Offset;
|
||
RtlMoveMemory(Buffer, ((PUCHAR) SlotInformation + Offset), DataLength);
|
||
}
|
||
|
||
return(DataLength);
|
||
}
|
||
#endif //NEC_98
|