|
|
/*++
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; }
|