/*++ Copyright (c) 1997 Microsoft Corporation Module Name: translate.c Abstract: This is the default pnp IRQ translator. Author: Andy Thornton (andrewth) 7-June-97 Environment: Kernel Mode Driver. Notes: This should only be temporary and will be replaced by a call into the HAL to retrieve its translators. Revision History: --*/ #pragma warning(disable:4214) // bit field types other than int #pragma warning(disable:4201) // nameless struct/union #pragma warning(disable:4115) // named type definition in parentheses #pragma warning(disable:4127) // condition expression is constant #include "ntos.h" #include "haldisp.h" #include // // Iteration macros // // // Control macro (used like a for loop) which iterates over all entries in // a standard doubly linked list. Head is the list head and the entries are of // type Type. A member called ListEntry is assumed to be the LIST_ENTRY // structure linking the entries together. Current contains a pointer to each // entry in turn. // #define FOR_ALL_IN_LIST(Type, Head, Current) \ for((Current) = CONTAINING_RECORD((Head)->Flink, Type, ListEntry); \ (Head) != &(Current)->ListEntry; \ (Current) = CONTAINING_RECORD((Current)->ListEntry.Flink, \ Type, \ ListEntry) \ ) // // Similar to the above only iteration is over an array of length _Size. // #define FOR_ALL_IN_ARRAY(_Array, _Size, _Current) \ for ( (_Current) = (_Array); \ (_Current) < (_Array) + (_Size); \ (_Current)++ ) // // As above only iteration begins with the entry _Current // #define FOR_REST_IN_ARRAY(_Array, _Size, _Current) \ for ( ; \ (_Current) < (_Array) + (_Size); \ (_Current)++ ) #define HAL_IRQ_TRANSLATOR_VERSION 0 NTSTATUS FstubTranslateResource( 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 ); NTSTATUS FstubTranslateRequirement ( IN PVOID Context, IN PIO_RESOURCE_DESCRIPTOR Source, IN PDEVICE_OBJECT PhysicalDeviceObject, OUT PULONG TargetCount, OUT PIO_RESOURCE_DESCRIPTOR *Target ); VOID FstubTranslatorNull( IN PVOID Context ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE,xHalGetInterruptTranslator) #pragma alloc_text(PAGE,FstubTranslateResource) #pragma alloc_text(PAGE,FstubTranslateRequirement) #pragma alloc_text(PAGE,FstubTranslatorNull) #endif NTSTATUS xHalGetInterruptTranslator( 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 (BridgeBusNumber); #if defined(NO_LEGACY_DRIVERS) UNREFERENCED_PARAMETER(ParentInterfaceType); UNREFERENCED_PARAMETER(ParentBusNumber); UNREFERENCED_PARAMETER(BridgeInterfaceType); UNREFERENCED_PARAMETER(Size); UNREFERENCED_PARAMETER(Version); UNREFERENCED_PARAMETER(Translator); return STATUS_SUCCESS; } #else UNREFERENCED_PARAMETER(ParentInterfaceType); UNREFERENCED_PARAMETER(ParentBusNumber); #if !DBG UNREFERENCED_PARAMETER(Version); UNREFERENCED_PARAMETER(Size); #endif ASSERT(Version == HAL_IRQ_TRANSLATOR_VERSION); ASSERT(Size >= sizeof (TRANSLATOR_INTERFACE)); switch (BridgeInterfaceType) { case Eisa: case Isa: case MicroChannel: case InterfaceTypeUndefined: // special "IDE" cookie // // Pass back an interface for an IRQ translator. // RtlZeroMemory(Translator, sizeof (TRANSLATOR_INTERFACE)); Translator->Size = sizeof (TRANSLATOR_INTERFACE); Translator->Version = HAL_IRQ_TRANSLATOR_VERSION; Translator->InterfaceReference = &FstubTranslatorNull; Translator->InterfaceDereference = &FstubTranslatorNull; Translator->TranslateResources = &FstubTranslateResource; Translator->TranslateResourceRequirements = &FstubTranslateRequirement; if (BridgeInterfaceType == InterfaceTypeUndefined) { Translator->Context = (PVOID)Isa; } else { Translator->Context = (PVOID)BridgeInterfaceType; } return STATUS_SUCCESS; default: return STATUS_NOT_IMPLEMENTED; } } NTSTATUS FstubTranslateResource( 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 ) { NTSTATUS status; ULONG affinity, currentVector, translatedVector; KIRQL irql; PIO_RESOURCE_DESCRIPTOR currentAlternative; PAGED_CODE(); UNREFERENCED_PARAMETER (PhysicalDeviceObject); ASSERT(Source->Type == CmResourceTypeInterrupt); status = STATUS_UNSUCCESSFUL; // // Copy unchanged fields // *Target = *Source; switch (Direction) { case TranslateChildToParent: // // Perform the translation - The interrupt source is // ISA. // Target->u.Interrupt.Vector = HalGetInterruptVector( (INTERFACE_TYPE)(ULONG_PTR)Context, 0, // assume bus 0 Source->u.Interrupt.Vector, Source->u.Interrupt.Vector, &irql, &affinity ); Target->u.Interrupt.Level = irql; Target->u.Interrupt.Affinity = affinity; status = STATUS_TRANSLATION_COMPLETE; break; case TranslateParentToChild: // // Translate each alternative and when we match then use the value we // just translated // FOR_ALL_IN_ARRAY(Alternatives, AlternativesCount, currentAlternative) { ASSERT(currentAlternative->Type == CmResourceTypeInterrupt); currentVector = currentAlternative->u.Interrupt.MinimumVector; while (currentVector <= currentAlternative->u.Interrupt.MaximumVector) { translatedVector = HalGetInterruptVector((INTERFACE_TYPE)(ULONG_PTR)Context, 0, // assume bus 0 currentVector, currentVector, &irql, &affinity ); if (translatedVector == Source->u.Interrupt.Vector) { // // We found our vector - fill in the target and return // Target->u.Interrupt.Vector = currentVector; Target->u.Interrupt.Level = Target->u.Interrupt.Vector; Target->u.Interrupt.Affinity = 0xFFFFFFFF; return STATUS_SUCCESS; } currentVector++; } } break; } return status; } NTSTATUS FstubTranslateRequirement ( IN PVOID Context, IN PIO_RESOURCE_DESCRIPTOR Source, IN PDEVICE_OBJECT PhysicalDeviceObject, OUT PULONG TargetCount, OUT PIO_RESOURCE_DESCRIPTOR *Target ) { ULONG affinity; KIRQL irql; PAGED_CODE(); UNREFERENCED_PARAMETER (PhysicalDeviceObject); ASSERT(Source->Type == CmResourceTypeInterrupt); *Target = ExAllocatePoolWithTag(PagedPool, sizeof(IO_RESOURCE_DESCRIPTOR), 'btsF' ); if (!*Target) { return STATUS_INSUFFICIENT_RESOURCES; } *TargetCount = 1; // // Copy unchanged fields // **Target = *Source; (*Target)->u.Interrupt.MinimumVector = HalGetInterruptVector( (INTERFACE_TYPE)(ULONG_PTR)Context, 0, // assume bus 0 Source->u.Interrupt.MinimumVector, Source->u.Interrupt.MinimumVector, &irql, &affinity ); (*Target)->u.Interrupt.MaximumVector = HalGetInterruptVector( (INTERFACE_TYPE)(ULONG_PTR)Context, 0, // assume bus 0 Source->u.Interrupt.MaximumVector, Source->u.Interrupt.MaximumVector, &irql, &affinity ); return STATUS_TRANSLATION_COMPLETE; } VOID FstubTranslatorNull( IN PVOID Context ) { PAGED_CODE(); UNREFERENCED_PARAMETER (Context); return; } #endif // NO_LEGACY_DRIVERS