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;
|
||
}
|
||
|
||
|