1068 lines
27 KiB
C
1068 lines
27 KiB
C
/*++
|
||
|
||
|
||
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";
|
||
ANSI_STRING TmpString;
|
||
ULONG BusNumber;
|
||
UCHAR BusString[] = "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] += (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
|
||
);
|
||
|
||
// 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);
|
||
if (BusName.Buffer) RtlFreeUnicodeString(&BusName);
|
||
|
||
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;
|
||
}
|
||
}
|