windows-nt/Source/XPSP1/NT/base/hals/halia64/ia64/ixisabus.c
2020-09-26 16:20:57 +08:00

818 lines
21 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
ixisabus.c
Abstract:
Author:
Environment:
Revision History:
--*/
#include "halp.h"
BOOLEAN
HalpTranslateIsaBusAddress (
IN PVOID BusHandler,
IN PVOID RootHandler,
IN PHYSICAL_ADDRESS BusAddress,
IN OUT PULONG AddressSpace,
OUT PPHYSICAL_ADDRESS TranslatedAddress
);
BOOLEAN
HalpTranslateEisaBusAddress (
IN PVOID BusHandler,
IN PVOID RootHandler,
IN PHYSICAL_ADDRESS BusAddress,
IN OUT PULONG AddressSpace,
OUT PPHYSICAL_ADDRESS TranslatedAddress
);
BOOLEAN
HalpTranslateSystemBusAddress (
IN PVOID BusHandler,
IN PVOID RootHandler,
IN PHYSICAL_ADDRESS BusAddress,
IN OUT PULONG AddressSpace,
OUT PPHYSICAL_ADDRESS TranslatedAddress
);
#ifdef EISA_SUPPORTED
ULONG
HalpGetEisaInterruptVector(
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN ULONG BusInterruptLevel,
IN ULONG BusInterruptVector,
OUT PKIRQL Irql,
OUT PKAFFINITY Affinity
);
NTSTATUS
HalpAdjustEisaResourceList (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
);
HalpGetEisaData (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN ULONG SlotNumber,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
);
extern USHORT HalpEisaIrqMask;
extern USHORT HalpEisaIrqIgnore;
#endif // EISA_SUPPORTED
#ifdef ALLOC_PRAGMA
#ifdef EISA_SUPPORTED
#pragma alloc_text(PAGE,HalpAdjustEisaResourceList)
#pragma alloc_text(PAGE,HalpRecordEisaInterruptVectors)
#pragma alloc_text(PAGE,HalpGetEisaInterruptVector)
#pragma alloc_text(PAGE,HalpGetEisaData)
#endif
#pragma alloc_text(PAGE,HalIrqTranslateResourceRequirementsIsa)
#pragma alloc_text(PAGE,HalIrqTranslateResourcesIsa)
#endif
#ifdef EISA_SUPPORTED
HalpGetEisaData (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN ULONG SlotNumber,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
)
/*++
Routine Description:
The function returns the Eisa bus data for a slot or address.
Arguments:
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.
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
OBJECT_ATTRIBUTES BusObjectAttributes;
PWSTR EisaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\EisaAdapter";
PWSTR ConfigData = L"Configuration Data";
ANSI_STRING TmpString;
ULONG BusNumber;
UCHAR BusString[] = "00";
UNICODE_STRING RootName, BusName;
UNICODE_STRING ConfigDataName;
NTSTATUS NtStatus;
PKEY_VALUE_FULL_INFORMATION ValueInformation;
PCM_FULL_RESOURCE_DESCRIPTOR Descriptor;
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResource;
PCM_EISA_SLOT_INFORMATION SlotInformation;
ULONG PartialCount;
ULONG TotalDataSize, SlotDataSize;
HANDLE EisaHandle, BusHandle;
ULONG BytesWritten, BytesNeeded;
PUCHAR KeyValueBuffer;
ULONG i;
ULONG DataLength = 0;
PUCHAR DataBuffer = Buffer;
BOOLEAN Found = FALSE;
PAGED_CODE ();
RtlInitUnicodeString(
&RootName,
EisaPath
);
InitializeObjectAttributes(
&ObjectAttributes,
&RootName,
OBJ_CASE_INSENSITIVE,
(HANDLE)NULL,
NULL
);
//
// Open the EISA root
//
NtStatus = ZwOpenKey(
&EisaHandle,
KEY_READ,
&ObjectAttributes
);
if (!NT_SUCCESS(NtStatus)) {
DataLength = 0;
goto HalpGetEisaDataExit;
}
//
// Init bus number path
//
BusNumber = BusHandler->BusNumber;
if (BusNumber > 99) {
DataLength = 0;
goto HalpGetEisaDataExit;
}
if (BusNumber > 9) {
BusString[0] += (UCHAR) (BusNumber/10);
BusString[1] += (UCHAR) (BusNumber % 10);
} else {
BusString[0] += (UCHAR) BusNumber;
BusString[1] = '\0';
}
RtlInitAnsiString(
&TmpString,
BusString
);
RtlAnsiStringToUnicodeString(
&BusName,
&TmpString,
TRUE
);
InitializeObjectAttributes(
&BusObjectAttributes,
&BusName,
OBJ_CASE_INSENSITIVE,
(HANDLE)EisaHandle,
NULL
);
//
// Open the EISA root + Bus Number
//
NtStatus = ZwOpenKey(
&BusHandle,
KEY_READ,
&BusObjectAttributes
);
if (!NT_SUCCESS(NtStatus)) {
HalDebugPrint(( HAL_INFO, "HAL: Opening Bus Number: Status = %x\n",NtStatus ));
DataLength = 0;
goto HalpGetEisaDataExit;
}
//
// opening the configuration data. This first call tells us how
// much memory we need to allocate
//
RtlInitUnicodeString(
&ConfigDataName,
ConfigData
);
//
// This should fail. We need to make this call so we can
// get the actual size of the buffer to allocate.
//
ValueInformation = (PKEY_VALUE_FULL_INFORMATION) &i;
NtStatus = ZwQueryValueKey(
BusHandle,
&ConfigDataName,
KeyValueFullInformation,
ValueInformation,
0,
&BytesNeeded
);
KeyValueBuffer = ExAllocatePoolWithTag(
NonPagedPool,
BytesNeeded,
HAL_POOL_TAG
);
if (KeyValueBuffer == NULL) {
HalDebugPrint(( HAL_INFO, "HAL: Cannot allocate Key Value Buffer\n" ));
ZwClose(BusHandle);
DataLength = 0;
goto HalpGetEisaDataExit;
}
ValueInformation = (PKEY_VALUE_FULL_INFORMATION)KeyValueBuffer;
NtStatus = ZwQueryValueKey(
BusHandle,
&ConfigDataName,
KeyValueFullInformation,
ValueInformation,
BytesNeeded,
&BytesWritten
);
ZwClose(BusHandle);
if (!NT_SUCCESS(NtStatus)) {
HalDebugPrint(( HAL_INFO, "HAL: Query Config Data: Status = %x\n",NtStatus ));
DataLength = 0;
goto HalpGetEisaDataExit;
}
//
// We get back a Full Resource Descriptor List
//
Descriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)ValueInformation +
ValueInformation->DataOffset);
PartialResource = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
&(Descriptor->PartialResourceList.PartialDescriptors);
PartialCount = Descriptor->PartialResourceList.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
//
DataLength = 0;
goto HalpGetEisaDataExit;
}
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:
HalDebugPrint(( HAL_INFO, "HAL: Bad Data in registry!\n" ));
DataLength = 0;
goto HalpGetEisaDataExit;
}
}
if (Found) {
i = Length + Offset;
if (i > SlotDataSize) {
i = SlotDataSize;
}
DataLength = i - Offset;
RtlMoveMemory (Buffer, ((PUCHAR)SlotInformation + Offset), DataLength);
}
HalpGetEisaDataExit:
if (KeyValueBuffer) ExFreePool(KeyValueBuffer);
RtlFreeUnicodeString(&BusName);
return DataLength;
}
#endif // EISA_SUPPORTED
NTSTATUS
HalIrqTranslateResourceRequirementsIsa(
IN PVOID Context,
IN PIO_RESOURCE_DESCRIPTOR Source,
IN PDEVICE_OBJECT PhysicalDeviceObject,
OUT PULONG TargetCount,
OUT PIO_RESOURCE_DESCRIPTOR *Target
)
/*++
Routine Description:
This function is basically a wrapper for
HalIrqTranslateResourceRequirementsRoot that understands
the weirdnesses of the ISA bus.
Arguments:
Return Value:
status
--*/
{
PIO_RESOURCE_DESCRIPTOR modSource, target, rootTarget;
NTSTATUS status;
BOOLEAN picSlaveDeleted = FALSE;
BOOLEAN deleteResource;
ULONG sourceCount = 0;
ULONG targetCount = 0;
ULONG resource;
ULONG rootCount;
ULONG invalidIrq;
PAGED_CODE();
ASSERT(Source->Type == CmResourceTypeInterrupt);
modSource = ExAllocatePoolWithTag(
NonPagedPool,
//
// we will have at most nine ranges when we are done
//
sizeof(IO_RESOURCE_DESCRIPTOR) * 9,
HAL_POOL_TAG
);
if (!modSource) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(modSource, sizeof(IO_RESOURCE_DESCRIPTOR) * 9);
//
// Is the PIC_SLAVE_IRQ in this resource?
//
if ((Source->u.Interrupt.MinimumVector <= PIC_SLAVE_IRQ) &&
(Source->u.Interrupt.MaximumVector >= PIC_SLAVE_IRQ)) {
//
// Clip the maximum
//
if (Source->u.Interrupt.MinimumVector < PIC_SLAVE_IRQ) {
modSource[sourceCount] = *Source;
modSource[sourceCount].u.Interrupt.MinimumVector =
Source->u.Interrupt.MinimumVector;
modSource[sourceCount].u.Interrupt.MaximumVector =
PIC_SLAVE_IRQ - 1;
sourceCount++;
}
//
// Clip the minimum
//
if (Source->u.Interrupt.MaximumVector > PIC_SLAVE_IRQ) {
modSource[sourceCount] = *Source;
modSource[sourceCount].u.Interrupt.MaximumVector =
Source->u.Interrupt.MaximumVector;
modSource[sourceCount].u.Interrupt.MinimumVector =
PIC_SLAVE_IRQ + 1;
sourceCount++;
}
//
// In ISA machines, the PIC_SLAVE_IRQ is rerouted
// to PIC_SLAVE_REDIRECT. So find out if PIC_SLAVE_REDIRECT
// is within this list. If it isn't we need to add it.
//
if (!((Source->u.Interrupt.MinimumVector <= PIC_SLAVE_REDIRECT) &&
(Source->u.Interrupt.MaximumVector >= PIC_SLAVE_REDIRECT))) {
modSource[sourceCount] = *Source;
modSource[sourceCount].u.Interrupt.MinimumVector=PIC_SLAVE_REDIRECT;
modSource[sourceCount].u.Interrupt.MaximumVector=PIC_SLAVE_REDIRECT;
sourceCount++;
}
} else {
*modSource = *Source;
sourceCount = 1;
}
//
// Now that the PIC_SLAVE_IRQ has been handled, we have
// to take into account IRQs that may have been steered
// away to the PCI bus.
//
// N.B. The algorithm used below may produce resources
// with minimums greater than maximums. Those will
// be stripped out later.
//
for (invalidIrq = 0; invalidIrq < PIC_VECTORS; invalidIrq++) {
//
// Look through all the resources, possibly removing
// this IRQ from them.
//
for (resource = 0; resource < sourceCount; resource++) {
deleteResource = FALSE;
if (HalpPciIrqMask & (1 << invalidIrq)) {
//
// This IRQ belongs to the PCI bus.
//
if (!((HalpBusType == MACHINE_TYPE_EISA) &&
((modSource[resource].Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)))) {
//
// And this resource is not an EISA-style,
// level-triggered interrupt.
//
// N.B. Only the system BIOS truely knows
// whether an IRQ on a PCI bus can be
// shared with an IRQ on an ISA bus.
// This code assumes that, in the case
// that the BIOS set an EISA device to
// the same interrupt as a PCI device,
// the machine can actually function.
//
deleteResource = TRUE;
}
}
#if !defined(MCA) && defined(EISA_SUPPORTED)
if ((HalpBusType == MACHINE_TYPE_EISA) &&
!(HalpEisaIrqIgnore & (1 << invalidIrq))) {
if (modSource[resource].Flags != HalpGetIsaIrqState(invalidIrq)) {
//
// This driver has requested a level-triggered interrupt
// and this particular interrupt is set to be edge, or
// vice-versa.
//
deleteResource = TRUE;
}
}
#endif
if (deleteResource) {
if (modSource[resource].u.Interrupt.MinimumVector == invalidIrq) {
modSource[resource].u.Interrupt.MinimumVector++;
} else if (modSource[resource].u.Interrupt.MaximumVector == invalidIrq) {
modSource[resource].u.Interrupt.MaximumVector--;
} else if ((modSource[resource].u.Interrupt.MinimumVector < invalidIrq) &&
(modSource[resource].u.Interrupt.MaximumVector > invalidIrq)) {
//
// Copy the current resource into a new resource.
//
modSource[sourceCount] = modSource[resource];
//
// Clip the current resource to a range below invalidIrq.
//
modSource[resource].u.Interrupt.MaximumVector = invalidIrq - 1;
//
// Clip the new resource to a range above invalidIrq.
//
modSource[sourceCount].u.Interrupt.MinimumVector = invalidIrq + 1;
sourceCount++;
}
}
}
}
target = ExAllocatePoolWithTag(PagedPool,
sizeof(IO_RESOURCE_DESCRIPTOR) * sourceCount,
HAL_POOL_TAG
);
if (!target) {
ExFreePool(modSource);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Now send each of these ranges through
// HalIrqTranslateResourceRequirementsRoot.
//
for (resource = 0; resource < sourceCount; resource++) {
//
// Skip over resources that we have previously
// clobbered (while deleting PCI IRQs.)
//
if (modSource[resource].u.Interrupt.MinimumVector >
modSource[resource].u.Interrupt.MaximumVector) {
continue;
}
status = HalIrqTranslateResourceRequirementsRoot(
Context,
&modSource[resource],
PhysicalDeviceObject,
&rootCount,
&rootTarget
);
if (!NT_SUCCESS(status)) {
ExFreePool(target);
goto HalIrqTranslateResourceRequirementsIsaExit;
}
//
// HalIrqTranslateResourceRequirementsRoot should return
// either one resource or, occasionally, zero.
//
ASSERT(rootCount <= 1);
if (rootCount == 1) {
target[targetCount] = *rootTarget;
targetCount++;
ExFreePool(rootTarget);
}
}
*TargetCount = targetCount;
if (targetCount > 0) {
*Target = target;
} else {
ExFreePool(target);
}
status = STATUS_TRANSLATION_COMPLETE;
HalIrqTranslateResourceRequirementsIsaExit:
ExFreePool(modSource);
return status;
}
NTSTATUS
HalIrqTranslateResourcesIsa(
IN PVOID Context,
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
IN RESOURCE_TRANSLATION_DIRECTION Direction,
IN ULONG AlternativesCount, OPTIONAL
IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
IN PDEVICE_OBJECT PhysicalDeviceObject,
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
)
/*++
Routine Description:
This function is basically a wrapper for
HalIrqTranslateResourcesRoot that understands
the weirdnesses of the ISA bus.
Arguments:
Return Value:
status
--*/
{
CM_PARTIAL_RESOURCE_DESCRIPTOR modSource;
NTSTATUS status;
BOOLEAN usePicSlave = FALSE;
ULONG i;
modSource = *Source;
if (Direction == TranslateChildToParent) {
if (Source->u.Interrupt.Vector == PIC_SLAVE_IRQ) {
modSource.u.Interrupt.Vector = PIC_SLAVE_REDIRECT;
modSource.u.Interrupt.Level = PIC_SLAVE_REDIRECT;
}
}
status = HalIrqTranslateResourcesRoot(
Context,
&modSource,
Direction,
AlternativesCount,
Alternatives,
PhysicalDeviceObject,
Target);
if (!NT_SUCCESS(status)) {
return status;
}
if (Direction == TranslateParentToChild) {
//
// Because the ISA interrupt controller is
// cascaded, there is one case where there is
// a two-to-one mapping for interrupt sources.
// (On a PC, both 2 and 9 trigger vector 9.)
//
// We need to account for this and deliver the
// right value back to the driver.
//
if (Target->u.Interrupt.Level == PIC_SLAVE_REDIRECT) {
//
// Search the Alternatives list. If it contains
// PIC_SLAVE_IRQ but not PIC_SLAVE_REDIRECT,
// we should return PIC_SLAVE_IRQ.
//
for (i = 0; i < AlternativesCount; i++) {
if ((Alternatives[i].u.Interrupt.MinimumVector >= PIC_SLAVE_REDIRECT) &&
(Alternatives[i].u.Interrupt.MaximumVector <= PIC_SLAVE_REDIRECT)) {
//
// The list contains, PIC_SLAVE_REDIRECT. Stop
// looking.
//
usePicSlave = FALSE;
break;
}
if ((Alternatives[i].u.Interrupt.MinimumVector >= PIC_SLAVE_IRQ) &&
(Alternatives[i].u.Interrupt.MaximumVector <= PIC_SLAVE_IRQ)) {
//
// The list contains, PIC_SLAVE_IRQ. Use it
// unless we find PIC_SLAVE_REDIRECT later.
//
usePicSlave = TRUE;
}
}
if (usePicSlave) {
Target->u.Interrupt.Level = PIC_SLAVE_IRQ;
Target->u.Interrupt.Vector = PIC_SLAVE_IRQ;
}
}
}
return status;
}