550 lines
14 KiB
C
550 lines
14 KiB
C
/*++
|
||
|
||
Copyright (c) 1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
pmapic.c
|
||
|
||
Abstract:
|
||
|
||
Implements functions specific to ISA busses
|
||
in ACPI-APIC machines.
|
||
|
||
Author:
|
||
|
||
Jake Oshins (jakeo) 11-October-1997
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "halp.h"
|
||
#include "acpitabl.h"
|
||
|
||
NTSTATUS
|
||
TranslateGlobalVectorToIsaVector(
|
||
IN ULONG GlobalVector,
|
||
OUT PULONG IsaVector
|
||
);
|
||
|
||
NTSTATUS
|
||
HalacpiIrqTranslateResourceRequirementsIsa(
|
||
IN PVOID Context,
|
||
IN PIO_RESOURCE_DESCRIPTOR Source,
|
||
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
||
OUT PULONG TargetCount,
|
||
OUT PIO_RESOURCE_DESCRIPTOR *Target
|
||
);
|
||
|
||
NTSTATUS
|
||
HalacpiIrqTranslateResourcesIsa(
|
||
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
|
||
);
|
||
|
||
extern ULONG HalpPicVectorRedirect[];
|
||
extern FADT HalpFixedAcpiDescTable;
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, TranslateGlobalVectorToIsaVector)
|
||
#pragma alloc_text(PAGE, HalacpiIrqTranslateResourceRequirementsIsa)
|
||
#pragma alloc_text(PAGE, HalacpiIrqTranslateResourcesIsa)
|
||
#pragma alloc_text(PAGE, HalacpiGetInterruptTranslator)
|
||
#endif
|
||
|
||
#define TranslateIsaVectorToGlobalVector(vector) \
|
||
(HalpPicVectorRedirect[vector])
|
||
|
||
NTSTATUS
|
||
TranslateGlobalVectorToIsaVector(
|
||
IN ULONG GlobalVector,
|
||
OUT PULONG IsaVector
|
||
)
|
||
{
|
||
UCHAR i;
|
||
|
||
for (i = 0; i < PIC_VECTORS; i++) {
|
||
|
||
if (HalpPicVectorRedirect[i] == GlobalVector) {
|
||
|
||
*IsaVector = i;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
}
|
||
|
||
return STATUS_NOT_FOUND;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
HalacpiIrqTranslateResourceRequirementsIsa(
|
||
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 deleteResource;
|
||
ULONG sourceCount = 0;
|
||
ULONG targetCount = 0;
|
||
ULONG resource, resourceLength;
|
||
ULONG rootCount;
|
||
ULONG irq, startIrq, endIrq;
|
||
ULONG maxTargets;
|
||
|
||
PAGED_CODE();
|
||
ASSERT(Source->Type == CmResourceTypeInterrupt);
|
||
|
||
maxTargets = Source->u.Interrupt.MaximumVector -
|
||
Source->u.Interrupt.MinimumVector + 3;
|
||
|
||
resourceLength = sizeof(IO_RESOURCE_DESCRIPTOR) * maxTargets;
|
||
|
||
modSource = ExAllocatePoolWithTag(PagedPool, resourceLength, HAL_POOL_TAG);
|
||
|
||
if (!modSource) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlZeroMemory(modSource, resourceLength);
|
||
|
||
//
|
||
// 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;
|
||
}
|
||
|
||
//
|
||
// Clip out the SCI vector, if it is here.
|
||
//
|
||
|
||
for (resource = 0; resource < sourceCount; resource++) {
|
||
|
||
if ((modSource[resource].u.Interrupt.MinimumVector <=
|
||
HalpFixedAcpiDescTable.sci_int_vector) &&
|
||
(modSource[resource].u.Interrupt.MaximumVector >=
|
||
HalpFixedAcpiDescTable.sci_int_vector)) {
|
||
|
||
//
|
||
// The SCI vector is within this range.
|
||
//
|
||
|
||
if (modSource[resource].u.Interrupt.MinimumVector <
|
||
HalpFixedAcpiDescTable.sci_int_vector) {
|
||
|
||
//
|
||
// Put a new range on the end of modSource.
|
||
//
|
||
|
||
modSource[sourceCount].u.Interrupt.MinimumVector =
|
||
modSource[resource].u.Interrupt.MinimumVector;
|
||
|
||
modSource[sourceCount].u.Interrupt.MaximumVector =
|
||
HalpFixedAcpiDescTable.sci_int_vector - 1;
|
||
|
||
sourceCount++;
|
||
}
|
||
|
||
if (modSource[resource].u.Interrupt.MaximumVector >
|
||
HalpFixedAcpiDescTable.sci_int_vector) {
|
||
|
||
//
|
||
// Put a new range on the end of modSource.
|
||
//
|
||
|
||
modSource[sourceCount].u.Interrupt.MinimumVector =
|
||
HalpFixedAcpiDescTable.sci_int_vector + 1;
|
||
|
||
modSource[sourceCount].u.Interrupt.MaximumVector =
|
||
modSource[resource].u.Interrupt.MaximumVector;
|
||
|
||
sourceCount++;
|
||
}
|
||
|
||
//
|
||
// Now remove the range that we just broke up.
|
||
//
|
||
|
||
RtlMoveMemory(modSource + resource,
|
||
modSource + resource + 1,
|
||
sizeof(IO_RESOURCE_DESCRIPTOR) *
|
||
(sourceCount - resource));
|
||
|
||
sourceCount--;
|
||
}
|
||
}
|
||
|
||
|
||
target = ExAllocatePoolWithTag(PagedPool, resourceLength, HAL_POOL_TAG);
|
||
|
||
if (!target) {
|
||
ExFreePool(modSource);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlZeroMemory(target, resourceLength);
|
||
|
||
//
|
||
// Now translate each range from ISA vectors to ACPI
|
||
// "global system interrupt vectors." Since GSIVs aren't
|
||
// necessarily contiguous with respect to the ISA vectors,
|
||
// this may involve breaking each range up into smaller
|
||
// ranges, each independently translated into the GSIV space.
|
||
//
|
||
for (resource = 0; resource < sourceCount; resource++) {
|
||
|
||
//
|
||
// For each existing resource, start with the minimum
|
||
// and maximum, unchanged.
|
||
//
|
||
|
||
irq = modSource[resource].u.Interrupt.MinimumVector;
|
||
endIrq = modSource[resource].u.Interrupt.MaximumVector;
|
||
|
||
do {
|
||
|
||
//
|
||
// Now cycle through every IRQ in this range, testing
|
||
// to see if its translated value is contiguous
|
||
// with respect to the translated value of the next
|
||
// IRQ in the range.
|
||
//
|
||
|
||
startIrq = irq;
|
||
|
||
for (; irq < endIrq; irq++) {
|
||
|
||
if (TranslateIsaVectorToGlobalVector(irq) + 1 !=
|
||
TranslateIsaVectorToGlobalVector(irq + 1)) {
|
||
|
||
//
|
||
// This range is not contiguous. Stop now
|
||
// and create a target range.
|
||
//
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Clone the source descriptor
|
||
//
|
||
target[targetCount] = *Source;
|
||
|
||
//
|
||
// Fill in the relevant changes.
|
||
//
|
||
target[targetCount].u.Interrupt.MinimumVector =
|
||
TranslateIsaVectorToGlobalVector(startIrq);
|
||
|
||
target[targetCount].u.Interrupt.MaximumVector =
|
||
TranslateIsaVectorToGlobalVector(irq);
|
||
|
||
ASSERT(target[targetCount].u.Interrupt.MinimumVector <=
|
||
target[targetCount].u.Interrupt.MaximumVector);
|
||
|
||
targetCount++;
|
||
|
||
} while (irq != endIrq);
|
||
}
|
||
|
||
*TargetCount = targetCount;
|
||
|
||
if (targetCount > 0) {
|
||
|
||
*Target = target;
|
||
|
||
} else {
|
||
|
||
ExFreePool(target);
|
||
}
|
||
|
||
ExFreePool(modSource);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
HalacpiIrqTranslateResourcesIsa(
|
||
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
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
BOOLEAN usePicSlave = FALSE;
|
||
ULONG i;
|
||
ULONG vector;
|
||
|
||
PAGED_CODE();
|
||
|
||
ASSERT(Source->Type == CmResourceTypeInterrupt);
|
||
|
||
//
|
||
// Copy everything
|
||
//
|
||
*Target = *Source;
|
||
|
||
switch (Direction) {
|
||
case TranslateChildToParent:
|
||
|
||
Target->u.Interrupt.Level =
|
||
TranslateIsaVectorToGlobalVector(Source->u.Interrupt.Level);
|
||
|
||
Target->u.Interrupt.Vector =
|
||
TranslateIsaVectorToGlobalVector(Source->u.Interrupt.Vector);
|
||
|
||
break;
|
||
|
||
case TranslateParentToChild:
|
||
|
||
status = TranslateGlobalVectorToIsaVector(Source->u.Interrupt.Level,
|
||
&vector);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
|
||
Target->u.Interrupt.Level = vector;
|
||
|
||
status = TranslateGlobalVectorToIsaVector(Source->u.Interrupt.Vector,
|
||
&vector);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
|
||
Target->u.Interrupt.Vector = vector;
|
||
|
||
//
|
||
// 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;
|
||
}
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
HalacpiGetInterruptTranslator(
|
||
IN INTERFACE_TYPE ParentInterfaceType,
|
||
IN ULONG ParentBusNumber,
|
||
IN INTERFACE_TYPE BridgeInterfaceType,
|
||
IN USHORT Size,
|
||
IN USHORT Version,
|
||
OUT PTRANSLATOR_INTERFACE Translator,
|
||
OUT PULONG BridgeBusNumber
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
ParentInterfaceType - The type of the bus the bridge lives on (normally PCI).
|
||
|
||
ParentBusNumber - The number of the bus the bridge lives on.
|
||
|
||
ParentSlotNumber - The slot number the bridge lives in (where valid).
|
||
|
||
BridgeInterfaceType - The bus type the bridge provides (ie ISA for a PCI-ISA bridge).
|
||
|
||
ResourceType - The resource type we want to translate.
|
||
|
||
Size - The size of the translator buffer.
|
||
|
||
Version - The version of the translator interface requested.
|
||
|
||
Translator - Pointer to the buffer where the translator should be returned
|
||
|
||
BridgeBusNumber - Pointer to where the bus number of the bridge bus should be returned
|
||
|
||
Return Value:
|
||
|
||
Returns the status of this operation.
|
||
|
||
--*/
|
||
{
|
||
PAGED_CODE();
|
||
|
||
UNREFERENCED_PARAMETER(ParentInterfaceType);
|
||
UNREFERENCED_PARAMETER(ParentBusNumber);
|
||
|
||
ASSERT(Version == HAL_IRQ_TRANSLATOR_VERSION);
|
||
ASSERT(Size >= sizeof (TRANSLATOR_INTERFACE));
|
||
|
||
switch (BridgeInterfaceType) {
|
||
case Eisa:
|
||
case Isa:
|
||
case InterfaceTypeUndefined: // special "IDE" cookie
|
||
|
||
//
|
||
// Pass back an interface for an IRQ translator for
|
||
// the (E)ISA interrupts.
|
||
//
|
||
RtlZeroMemory(Translator, sizeof (TRANSLATOR_INTERFACE));
|
||
|
||
Translator->Size = sizeof (TRANSLATOR_INTERFACE);
|
||
Translator->Version = HAL_IRQ_TRANSLATOR_VERSION;
|
||
Translator->InterfaceReference = &HalTranslatorReference;
|
||
Translator->InterfaceDereference = &HalTranslatorDereference;
|
||
Translator->TranslateResources = &HalacpiIrqTranslateResourcesIsa;
|
||
Translator->TranslateResourceRequirements = &HalacpiIrqTranslateResourceRequirementsIsa;
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
default:
|
||
return STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
}
|