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