Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1058 lines
28 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
ixisabus.c
Abstract:
Author:
Environment:
Revision History:
--*/
#include "halp.h"
ULONG
HalpGetEisaInterruptVector(
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN ULONG BusInterruptLevel,
IN ULONG BusInterruptVector,
OUT PKIRQL Irql,
OUT PKAFFINITY Affinity
);
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
);
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;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,HalpGetEisaInterruptVector)
#pragma alloc_text(PAGE,HalpAdjustEisaResourceList)
#pragma alloc_text(PAGE,HalpGetEisaData)
#pragma alloc_text(PAGE,HalIrqTranslateResourceRequirementsIsa)
#pragma alloc_text(PAGE,HalIrqTranslateResourcesIsa)
#pragma alloc_text(PAGE,HalpRecordEisaInterruptVectors)
#endif
#ifndef ACPI_HAL
ULONG
HalpGetEisaInterruptVector(
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN ULONG BusInterruptLevel,
IN ULONG BusInterruptVector,
OUT PKIRQL Irql,
OUT PKAFFINITY Affinity
)
/*++
Routine Description:
This function returns the system interrupt vector and IRQL level
corresponding to the specified bus interrupt level and/or vector. The
system interrupt vector and IRQL are suitable for use in a subsequent call
to KeInitializeInterrupt.
Arguments:
BusHandle - Per bus specific structure
Irql - Returns the system request priority.
Affinity - Returns the system wide irq affinity.
Return Value:
Returns the system interrupt vector corresponding to the specified device.
--*/
{
UNREFERENCED_PARAMETER( BusInterruptVector );
//
// On standard PCs, IRQ 2 is the cascaded interrupt, and it really shows
// up on IRQ 9.
//
#if defined(NEC_98)
if (BusInterruptLevel == 7) {
BusInterruptLevel = 8;
}
#else // defined(NEC_98)
if (BusInterruptLevel == 2) {
BusInterruptLevel = 9;
}
#endif // defined(NEC_98)
if (BusInterruptLevel > 15) {
return 0;
}
//
// Get parent's translation from here..
//
return BusHandler->ParentHandler->GetInterruptVector (
BusHandler->ParentHandler,
RootHandler,
BusInterruptLevel,
BusInterruptVector,
Irql,
Affinity
);
}
NTSTATUS
HalpAdjustEisaResourceList (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
)
{
SUPPORTED_RANGE InterruptRange;
RtlZeroMemory (&InterruptRange, sizeof InterruptRange);
InterruptRange.Base = 0;
InterruptRange.Limit = 15;
return HaliAdjustResourceListRange (
BusHandler->BusAddresses,
&InterruptRange,
pResourceList
);
}
BOOLEAN
HalpTranslateIsaBusAddress(
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
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:
BusAddress - Supplies the bus-relative address
AddressSpace - Supplies the address space number.
Returns the host address space number.
AddressSpace == 0 => memory space
AddressSpace == 1 => I/O space
TranslatedAddress - Supplies a pointer to return the translated address
Return Value:
A return value of TRUE indicates that a system physical address
corresponding to the supplied bus relative address and bus address
number has been returned in TranslatedAddress.
A return value of FALSE occurs if the translation for the address was
not possible
--*/
{
BOOLEAN Status;
//
// Translated normally
//
Status = HalpTranslateSystemBusAddress (
BusHandler,
RootHandler,
BusAddress,
AddressSpace,
TranslatedAddress
);
//
// If it could not be translated, and it's memory space
// then we allow the translation as it would occur on it's
// corrisponding EISA bus. We're allowing this because
// many VLBus drivers are claiming to be ISA devices.
// (yes, they should claim to be VLBus devices, but VLBus is
// run by video cards and like everything else about video
// there's no hope of fixing it. (At least according to
// Andre))
//
if (Status == FALSE && *AddressSpace == 0) {
Status = HalTranslateBusAddress (
Eisa,
BusHandler->BusNumber,
BusAddress,
AddressSpace,
TranslatedAddress
);
}
return Status;
}
BOOLEAN
HalpTranslateEisaBusAddress(
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
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:
BusAddress - Supplies the bus-relative address
AddressSpace - Supplies the address space number.
Returns the host address space number.
AddressSpace == 0 => memory space
AddressSpace == 1 => I/O space
TranslatedAddress - Supplies a pointer to return the translated address
Return Value:
A return value of TRUE indicates that a system physical address
corresponding to the supplied bus relative address and bus address
number has been returned in TranslatedAddress.
A return value of FALSE occurs if the translation for the address was
not possible
--*/
{
BOOLEAN Status;
//
// Translated normally
//
Status = HalpTranslateSystemBusAddress (
BusHandler,
RootHandler,
BusAddress,
AddressSpace,
TranslatedAddress
);
//
// If it could not be translated, and it's in the 640k - 1m
// range then (for compatibility) try translating it on the
// Internal bus for
//
if (Status == FALSE &&
*AddressSpace == 0 &&
BusAddress.HighPart == 0 &&
BusAddress.LowPart >= 0xA0000 &&
BusAddress.LowPart < 0xFFFFF) {
Status = HalTranslateBusAddress (
Internal,
0,
BusAddress,
AddressSpace,
TranslatedAddress
);
}
return Status;
}
#endif
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";
ULONG BusNumber;
WCHAR BusString[] = L"00";
UNICODE_STRING RootName, BusName = {0};
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 = INVALID_HANDLE;
HANDLE BusHandle = INVALID_HANDLE;
ULONG BytesWritten, BytesNeeded;
PUCHAR KeyValueBuffer = NULL;
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] += (WCHAR) (BusNumber/10);
BusString[1] += (WCHAR) (BusNumber % 10);
} else {
BusString[0] += (WCHAR) BusNumber;
BusString[1] = '\0';
}
RtlInitUnicodeString(
&BusName,
BusString
);
InitializeObjectAttributes(
&BusObjectAttributes,
&BusName,
OBJ_CASE_INSENSITIVE,
(HANDLE)EisaHandle,
NULL
);
//
// Open the EISA root + Bus Number
//
NtStatus = ZwOpenKey(
&BusHandle,
KEY_READ,
&BusObjectAttributes
);
// Done with Eisa Handle
ZwClose(EisaHandle);
EisaHandle = INVALID_HANDLE;
if (!NT_SUCCESS(NtStatus)) {
DbgPrint("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) {
#if DBG
DbgPrint("HAL: Cannot allocate Key Value Buffer\n");
#endif
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)) {
#if DBG
DbgPrint("HAL: Query Config Data: Status = %x\n",NtStatus);
#endif
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:
#if DBG
DbgPrint("Bad Data in registry!\n");
#endif
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 (EisaHandle != INVALID_HANDLE)
{
ZwClose(EisaHandle);
}
if (KeyValueBuffer) ExFreePool(KeyValueBuffer);
return DataLength;
}
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;
BOOLEAN pciIsaConflict = FALSE;
PAGED_CODE();
ASSERT(Source->Type == CmResourceTypeInterrupt);
modSource = ExAllocatePoolWithTag(PagedPool,
// 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;
}
}
#ifndef MCA
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;
pciIsaConflict = 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);
}
}
status = STATUS_TRANSLATION_COMPLETE;
*TargetCount = targetCount;
if (targetCount > 0) {
*Target = target;
} else {
ExFreePool(target);
if (pciIsaConflict == TRUE) {
status = STATUS_PNP_IRQ_TRANSLATION_FAILED;
}
}
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;
}
VOID
HalpRecordEisaInterruptVectors(
VOID
)
{
HalpEisaIrqMask = READ_PORT_UCHAR((PUCHAR)EISA_EDGE_LEVEL0) & 0xff;
HalpEisaIrqMask |= READ_PORT_UCHAR((PUCHAR)EISA_EDGE_LEVEL1) << 8;
if ((HalpEisaIrqMask == 0xffff) ||
(HalpEisaIrqMask == 0x0000)) {
HalpEisaIrqIgnore = 0xffff;
}
}