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