818 lines
21 KiB
C
818 lines
21 KiB
C
|
/*++
|
|||
|
|
|||
|
|
|||
|
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;
|
|||
|
}
|
|||
|
|
|||
|
|