From 8ed43b69073f47c25bb1c2ff644a3dc948f017bc Mon Sep 17 00:00:00 2001 From: Dmitry Borisov Date: Sat, 20 Mar 2021 20:51:29 +0600 Subject: [PATCH] [ISAPNP] Fix descriptors and support alternative configurations - Fix empty resource descriptors being created. - Properly support IRQ descriptors. - Introduce four helpers made to help search descriptors in the logical device's requirements. - Implement support for memory descriptors and alternative configurations. - DMA descriptors are always DMA_8. --- drivers/bus/isapnp/isapnp.c | 893 +++++++++++++++++++++++++++++++----- drivers/bus/isapnp/isapnp.h | 35 ++ 2 files changed, 816 insertions(+), 112 deletions(-) diff --git a/drivers/bus/isapnp/isapnp.c b/drivers/bus/isapnp/isapnp.c index 842929ee0ce..343a0ca69b3 100644 --- a/drivers/bus/isapnp/isapnp.c +++ b/drivers/bus/isapnp/isapnp.c @@ -11,6 +11,8 @@ #include "isapnp.h" +#include + #define NDEBUG #include @@ -24,8 +26,168 @@ BOOLEAN ReadPortCreated = FALSE; _Guarded_by_(BusSyncEvent) LIST_ENTRY BusListHead; +static PUCHAR Priority; + /* FUNCTIONS ******************************************************************/ +static +CODE_SEG("PAGE") +int +__cdecl +IsaComparePriority( + const void *A, + const void *B) +{ + PAGED_CODE(); + + return Priority[*(PUCHAR)A] - Priority[*(PUCHAR)B]; +} + +static +CODE_SEG("PAGE") +VOID +IsaDetermineBestConfig( + _Out_writes_all_(ISAPNP_MAX_ALTERNATIVES) PUCHAR BestConfig, + _In_ PISAPNP_ALTERNATIVES Alternatives) +{ + UCHAR i; + + PAGED_CODE(); + + for (i = 0; i < ISAPNP_MAX_ALTERNATIVES; i++) + { + BestConfig[i] = i; + } + + Priority = Alternatives->Priority; + qsort(BestConfig, + Alternatives->Count, + sizeof(*BestConfig), + IsaComparePriority); +} + +static +CODE_SEG("PAGE") +VOID +IsaConvertIoRequirement( + _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor, + _In_ PISAPNP_IO_DESCRIPTION Description) +{ + PAGED_CODE(); + + Descriptor->Type = CmResourceTypePort; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_PORT_IO; + if (Description->Information & 0x1) + Descriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE; + else + Descriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE; + Descriptor->u.Port.Length = Description->Length; + Descriptor->u.Port.Alignment = Description->Alignment; + Descriptor->u.Port.MinimumAddress.LowPart = Description->Minimum; + Descriptor->u.Port.MaximumAddress.LowPart = Description->Maximum + + Description->Length - 1; +} + +static +CODE_SEG("PAGE") +VOID +IsaConvertIrqRequirement( + _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor, + _In_ PISAPNP_IRQ_DESCRIPTION Description, + _In_ ULONG Vector, + _In_ BOOLEAN FirstDescriptor) +{ + PAGED_CODE(); + + if (!FirstDescriptor) + Descriptor->Option = IO_RESOURCE_ALTERNATIVE; + Descriptor->Type = CmResourceTypeInterrupt; + if (Description->Information & 0xC) + { + Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + Descriptor->ShareDisposition = CmResourceShareShared; + } + else + { + Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + } + Descriptor->u.Interrupt.MinimumVector = + Descriptor->u.Interrupt.MaximumVector = Vector; +} + +static +CODE_SEG("PAGE") +VOID +IsaConvertDmaRequirement( + _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor, + _In_ PISAPNP_DMA_DESCRIPTION Description, + _In_ ULONG Channel, + _In_ BOOLEAN FirstDescriptor) +{ + UNREFERENCED_PARAMETER(Description); + + PAGED_CODE(); + + if (!FirstDescriptor) + Descriptor->Option = IO_RESOURCE_ALTERNATIVE; + Descriptor->Type = CmResourceTypeDma; + Descriptor->ShareDisposition = CmResourceShareUndetermined; + Descriptor->Flags = CM_RESOURCE_DMA_8; /* Ignore information byte for compatibility */ + Descriptor->u.Dma.MinimumChannel = + Descriptor->u.Dma.MaximumChannel = Channel; +} + +static +CODE_SEG("PAGE") +VOID +IsaConvertMemRangeRequirement( + _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor, + _In_ PISAPNP_MEMRANGE_DESCRIPTION Description) +{ + PAGED_CODE(); + + Descriptor->Type = CmResourceTypeMemory; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_MEMORY_24; + if ((Description->Information & 0x40) || !(Description->Information & 0x01)) + Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + Descriptor->u.Memory.Length = Description->Length << 8; + if (Description->Alignment == 0) + Descriptor->u.Memory.Alignment = 0x10000; + else + Descriptor->u.Memory.Alignment = Description->Alignment; + Descriptor->u.Memory.MinimumAddress.LowPart = Description->Minimum << 8; + Descriptor->u.Memory.MaximumAddress.LowPart = (Description->Maximum << 8) + + (Description->Length << 8) - 1; +} + +static +CODE_SEG("PAGE") +VOID +IsaConvertMemRange32Requirement( + _Out_ PIO_RESOURCE_DESCRIPTOR Descriptor, + _In_ PISAPNP_MEMRANGE32_DESCRIPTION Description) +{ + PAGED_CODE(); + + Descriptor->Type = CmResourceTypeMemory; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_MEMORY_24; + if ((Description->Information & 0x40) || !(Description->Information & 0x01)) + Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + Descriptor->u.Memory.Length = Description->Length; + Descriptor->u.Memory.Alignment = Description->Alignment; + Descriptor->u.Memory.MinimumAddress.LowPart = Description->Minimum; + Descriptor->u.Memory.MaximumAddress.LowPart = Description->Maximum + + Description->Length - 1; +} + static CODE_SEG("PAGE") NTSTATUS @@ -33,63 +195,133 @@ IsaPnpCreateLogicalDeviceRequirements( _In_ PISAPNP_PDO_EXTENSION PdoExt) { PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice; - RTL_BITMAP IrqBitmap[RTL_NUMBER_OF(LogDev->Irq)]; - RTL_BITMAP DmaBitmap[RTL_NUMBER_OF(LogDev->Dma)]; - ULONG IrqData[RTL_NUMBER_OF(LogDev->Irq)]; - ULONG DmaData[RTL_NUMBER_OF(LogDev->Dma)]; - ULONG ResourceCount = 0; + RTL_BITMAP TempBitmap; + ULONG TempBuffer; + ULONG ResourceCount = 0, AltCount = 0, AltOptionalCount = 0; ULONG ListSize, i, j; - BOOLEAN FirstIrq = TRUE, FirstDma = TRUE; + BOOLEAN FirstDescriptor; PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList; PIO_RESOURCE_DESCRIPTOR Descriptor; + PISAPNP_ALTERNATIVES Alternatives = LogDev->Alternatives; PAGED_CODE(); /* Count number of requirements */ for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++) { + /* + * Use the continue statement to count the number of requirements. + * We handle a possible gap because depedent function can appear at + * any position in the logical device's requirements list. + */ if (!LogDev->Io[i].Description.Length) - break; + continue; ResourceCount++; } for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++) { if (!LogDev->Irq[i].Description.Mask) - break; + continue; - IrqData[i] = LogDev->Irq[i].Description.Mask; - RtlInitializeBitMap(&IrqBitmap[i], &IrqData[i], 16); - ResourceCount += RtlNumberOfSetBits(&IrqBitmap[i]); + TempBuffer = LogDev->Irq[i].Description.Mask; + RtlInitializeBitMap(&TempBitmap, + &TempBuffer, + RTL_BITS_OF(LogDev->Irq[i].Description.Mask)); + ResourceCount += RtlNumberOfSetBits(&TempBitmap); + } + for (i = 0; i < RTL_NUMBER_OF(LogDev->Dma); i++) + { + if (!LogDev->Dma[i].Description.Mask) + continue; - if (LogDev->Irq[i].Description.Information & 0x4) + TempBuffer = LogDev->Dma[i].Description.Mask; + RtlInitializeBitMap(&TempBitmap, + &TempBuffer, + RTL_BITS_OF(LogDev->Dma[i].Description.Mask)); + ResourceCount += RtlNumberOfSetBits(&TempBitmap); + } + for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange); i++) + { + if (!LogDev->MemRange[i].Description.Length) + continue; + + ResourceCount++; + } + for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange32); i++) + { + if (!LogDev->MemRange32[i].Description.Length) + continue; + + ResourceCount++; + } + if (Alternatives) + { + ULONG BitCount; + + if (HasIoAlternatives(Alternatives)) + AltCount++; + if (HasIrqAlternatives(Alternatives)) + AltCount++; + if (HasDmaAlternatives(Alternatives)) + AltCount++; + if (HasMemoryAlternatives(Alternatives)) + AltCount++; + if (HasMemory32Alternatives(Alternatives)) + AltCount++; + ResourceCount += AltCount; + + if (HasIrqAlternatives(Alternatives)) { - /* Add room for level sensitive */ - ResourceCount += RtlNumberOfSetBits(&IrqBitmap[i]); + for (i = 0; i < Alternatives->Count; i++) + { + TempBuffer = Alternatives->Irq[i].Mask; + RtlInitializeBitMap(&TempBitmap, + &TempBuffer, + RTL_BITS_OF(Alternatives->Irq[i].Mask)); + BitCount = RtlNumberOfSetBits(&TempBitmap); + + if (BitCount > 1) + AltOptionalCount += BitCount - 1; + } + } + if (HasDmaAlternatives(Alternatives)) + { + for (i = 0; i < Alternatives->Count; i++) + { + TempBuffer = Alternatives->Dma[i].Mask; + RtlInitializeBitMap(&TempBitmap, + &TempBuffer, + RTL_BITS_OF(Alternatives->Dma[i].Mask)); + BitCount = RtlNumberOfSetBits(&TempBitmap); + + if (BitCount > 1) + AltOptionalCount += BitCount - 1; + } } } if (ResourceCount == 0) return STATUS_SUCCESS; - for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++) - { - if (!LogDev->Dma[i].Description.Mask) - break; - - DmaData[i] = LogDev->Dma[i].Description.Mask; - RtlInitializeBitMap(&DmaBitmap[i], &DmaData[i], 8); - ResourceCount += RtlNumberOfSetBits(&DmaBitmap[i]); - } /* Allocate memory to store requirements */ - ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) - + ResourceCount * sizeof(IO_RESOURCE_DESCRIPTOR); + ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST); + if (Alternatives) + { + ListSize += sizeof(IO_RESOURCE_DESCRIPTOR) * (ResourceCount - 1) * Alternatives->Count + + sizeof(IO_RESOURCE_LIST) * (Alternatives->Count - 1) + + sizeof(IO_RESOURCE_DESCRIPTOR) * AltOptionalCount; + } + else + { + ListSize += sizeof(IO_RESOURCE_DESCRIPTOR) * (ResourceCount - 1); + } RequirementsList = ExAllocatePoolZero(PagedPool, ListSize, TAG_ISAPNP); if (!RequirementsList) return STATUS_NO_MEMORY; RequirementsList->ListSize = ListSize; RequirementsList->InterfaceType = Isa; - RequirementsList->AlternativeLists = 1; + RequirementsList->AlternativeLists = Alternatives ? Alternatives->Count : 1; RequirementsList->List[0].Version = 1; RequirementsList->List[0].Revision = 1; @@ -102,94 +334,178 @@ IsaPnpCreateLogicalDeviceRequirements( if (!LogDev->Io[i].Description.Length) break; - DPRINT("Device.Io[%d].Information = 0x%02x\n", i, LogDev->Io[i].Description.Information); - DPRINT("Device.Io[%d].Minimum = 0x%02x\n", i, LogDev->Io[i].Description.Minimum); - DPRINT("Device.Io[%d].Maximum = 0x%02x\n", i, LogDev->Io[i].Description.Maximum); - DPRINT("Device.Io[%d].Alignment = 0x%02x\n", i, LogDev->Io[i].Description.Alignment); - DPRINT("Device.Io[%d].Length = 0x%02x\n", i, LogDev->Io[i].Description.Length); - - Descriptor->Type = CmResourceTypePort; - Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; - if (LogDev->Io[i].Description.Information & 0x1) - Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE; - else - Descriptor->Flags = CM_RESOURCE_PORT_10_BIT_DECODE; - Descriptor->u.Port.Length = LogDev->Io[i].Description.Length; - Descriptor->u.Port.Alignment = LogDev->Io[i].Description.Alignment; - Descriptor->u.Port.MinimumAddress.LowPart = LogDev->Io[i].Description.Minimum; - Descriptor->u.Port.MaximumAddress.LowPart = - LogDev->Io[i].Description.Maximum + LogDev->Io[i].Description.Length - 1; - Descriptor++; + IsaConvertIoRequirement(Descriptor++, &LogDev->Io[i].Description); } for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++) { if (!LogDev->Irq[i].Description.Mask) - break; + continue; - DPRINT("Device.Irq[%d].Mask = 0x%02x\n", i, LogDev->Irq[i].Description.Mask); - DPRINT("Device.Irq[%d].Information = 0x%02x\n", i, LogDev->Irq[i].Description.Information); + FirstDescriptor = TRUE; - for (j = 0; j < 15; j++) + for (j = 0; j < RTL_BITS_OF(LogDev->Irq[i].Description.Mask); j++) { - if (!RtlCheckBit(&IrqBitmap[i], j)) + if (!(LogDev->Irq[i].Description.Mask & (1 << j))) continue; - if (FirstIrq) - FirstIrq = FALSE; - else - Descriptor->Option = IO_RESOURCE_ALTERNATIVE; - Descriptor->Type = CmResourceTypeInterrupt; - Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED; - Descriptor->u.Interrupt.MinimumVector = Descriptor->u.Interrupt.MaximumVector = j; - Descriptor++; + IsaConvertIrqRequirement(Descriptor++, + &LogDev->Irq[i].Description, + j, + FirstDescriptor); - if (LogDev->Irq[i].Description.Information & 0x4) - { - /* Level interrupt */ - Descriptor->Option = IO_RESOURCE_ALTERNATIVE; - Descriptor->Type = CmResourceTypeInterrupt; - Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; - Descriptor->u.Interrupt.MinimumVector = Descriptor->u.Interrupt.MaximumVector = j; - Descriptor++; - } + if (FirstDescriptor) + FirstDescriptor = FALSE; } } for (i = 0; i < RTL_NUMBER_OF(LogDev->Dma); i++) { if (!LogDev->Dma[i].Description.Mask) - break; + continue; - DPRINT("Device.Dma[%d].Mask = 0x%02x\n", i, LogDev->Dma[i].Description.Mask); - DPRINT("Device.Dma[%d].Information = 0x%02x\n", i, LogDev->Dma[i].Description.Information); + FirstDescriptor = TRUE; - for (j = 0; j < 8; j++) + for (j = 0; j < RTL_BITS_OF(LogDev->Dma[i].Description.Mask); j++) { - if (!RtlCheckBit(&DmaBitmap[i], j)) + if (!(LogDev->Dma[i].Description.Mask & (1 << j))) continue; - if (FirstDma) - FirstDma = FALSE; - else - Descriptor->Option = IO_RESOURCE_ALTERNATIVE; - Descriptor->Type = CmResourceTypeDma; - switch (LogDev->Dma[i].Description.Information & 0x3) + IsaConvertDmaRequirement(Descriptor++, + &LogDev->Dma[i].Description, + j, + FirstDescriptor); + + if (FirstDescriptor) + FirstDescriptor = FALSE; + } + } + for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange); i++) + { + if (!LogDev->MemRange[i].Description.Length) + continue; + + IsaConvertMemRangeRequirement(Descriptor++, + &LogDev->MemRange[i].Description); + } + for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange32); i++) + { + if (!LogDev->MemRange32[i].Description.Length) + continue; + + IsaConvertMemRange32Requirement(Descriptor++, + &LogDev->MemRange32[i].Description); + } + if (Alternatives) + { + UCHAR BestConfig[ISAPNP_MAX_ALTERNATIVES]; + PIO_RESOURCE_LIST AltList = &RequirementsList->List[0]; + PIO_RESOURCE_LIST NextList = AltList; + + IsaDetermineBestConfig(BestConfig, Alternatives); + + for (i = 0; i < RequirementsList->AlternativeLists; i++) + { + RtlMoveMemory(NextList, AltList, sizeof(IO_RESOURCE_LIST)); + + /* Just because the 'NextList->Count++' correction */ + NextList->Count = ResourceCount; + /* + * For example, the ROM + * 0x15, ... // Logical device ID + * 0x30, // Start DF + * 0x22, 0x04, 0x00 // IRQ + * 0x30, // Start DF + * 0x22, 0xC0, 0x00 // IRQ + * 0x38, // End DF + * 0x2A, 0x20, 0x3A // DMA + * 0x22, 0x00, 0x08 // IRQ + * 0x79, 0x00 // END + * + * will be represented as the following resource requirements list: + * Interface 1 Bus 0 Slot 0 AlternativeLists 2 + * AltList 1, AltList->Count 3 + * [Option 0, ShareDisposition 1, Flags 1] INT: Min B Max B + * [Option 0, ShareDisposition 0, Flags 0] DMA: Min 5 Max 5 + * [Option 0, ShareDisposition 1, Flags 1] INT: Min 2 Max 2 + * End Descriptors + * AltList 2, AltList->Count 4 + * [Option 0, ShareDisposition 1, Flags 1] INT: Min B Max B + * [Option 0, ShareDisposition 0, Flags 0] DMA: Min 5 Max 5 + * [Option 0, ShareDisposition 1, Flags 1] INT: Min 6 Max 6 + * [Option 8, ShareDisposition 1, Flags 1] INT: Min 7 Max 7 + * End Descriptors + */ + + /* Propagate the fixed resources to our new list */ + for (j = 0; j < AltList->Count - AltCount; j++) { - case 0x0: Descriptor->Flags |= CM_RESOURCE_DMA_8; break; - case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_8_AND_16; break; - case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_16; break; - default: break; + RtlMoveMemory(&NextList->Descriptors[j], + &AltList->Descriptors[j], + sizeof(IO_RESOURCE_DESCRIPTOR)); } - if (LogDev->Dma[i].Description.Information & 0x4) - Descriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER; - switch ((LogDev->Dma[i].Description.Information >> 5) & 0x3) + + Descriptor = &NextList->Descriptors[NextList->Count - AltCount]; + + /* + * Append alternatives. + * NOTE: To keep it simple, we append these to the end of the list. + */ + if (HasIoAlternatives(Alternatives)) { - case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_A; break; - case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_B; break; - case 0x3: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_F; break; - default: break; + IsaConvertIoRequirement(Descriptor++, + &Alternatives->Io[BestConfig[i]]); } - Descriptor->u.Dma.MinimumChannel = Descriptor->u.Dma.MaximumChannel = j; - Descriptor++; + if (HasIrqAlternatives(Alternatives)) + { + FirstDescriptor = TRUE; + + for (j = 0; j < RTL_BITS_OF(Alternatives->Irq[BestConfig[i]].Mask); j++) + { + if (!(Alternatives->Irq[BestConfig[i]].Mask & (1 << j))) + continue; + + IsaConvertIrqRequirement(Descriptor++, + &Alternatives->Irq[BestConfig[i]], + j, + FirstDescriptor); + + if (FirstDescriptor) + FirstDescriptor = FALSE; + else + NextList->Count++; + } + } + if (HasDmaAlternatives(Alternatives)) + { + FirstDescriptor = TRUE; + + for (j = 0; j < RTL_BITS_OF(Alternatives->Dma[BestConfig[i]].Mask); j++) + { + if (!(Alternatives->Dma[BestConfig[i]].Mask & (1 << j))) + continue; + + IsaConvertDmaRequirement(Descriptor++, + &Alternatives->Dma[BestConfig[i]], + j, + FirstDescriptor); + + if (FirstDescriptor) + FirstDescriptor = FALSE; + else + NextList->Count++; + } + } + if (HasMemoryAlternatives(Alternatives)) + { + IsaConvertMemRangeRequirement(Descriptor++, + &Alternatives->MemRange[BestConfig[i]]); + } + if (HasMemory32Alternatives(Alternatives)) + { + IsaConvertMemRange32Requirement(Descriptor++, + &Alternatives->MemRange32[BestConfig[i]]); + } + + NextList = (PIO_RESOURCE_LIST)(NextList->Descriptors + NextList->Count); } } @@ -197,6 +513,275 @@ IsaPnpCreateLogicalDeviceRequirements( return STATUS_SUCCESS; } +CODE_SEG("PAGE") +BOOLEAN +FindIoDescriptor( + _In_ PISAPNP_LOGICAL_DEVICE LogDevice, + _In_opt_ ULONG Base, + _In_ ULONG RangeStart, + _In_ ULONG RangeEnd, + _Out_opt_ PUCHAR Information, + _Out_opt_ PULONG Length, + _Out_opt_ PUCHAR WriteOrder) +{ + ULONG i; + BOOLEAN Match; + PISAPNP_IO_DESCRIPTION Description; + + PAGED_CODE(); + + for (i = 0; i < RTL_NUMBER_OF(LogDevice->Io); i++) + { + Description = &LogDevice->Io[i].Description; + + Match = Base ? (Base >= Description->Minimum) && (Base <= Description->Maximum) + : (RangeStart >= Description->Minimum) && + (RangeEnd <= (ULONG)(Description->Maximum + Description->Length - 1)); + + if (Match) + { + if (Information) + *Information = Description->Information; + if (Length) + *Length = Description->Length; + if (WriteOrder) + *WriteOrder = LogDevice->Io[i].Index; + + return TRUE; + } + } + + if (!LogDevice->Alternatives) + return FALSE; + + for (i = 0; i < LogDevice->Alternatives->Count; i++) + { + Description = &LogDevice->Alternatives->Io[i]; + + Match = Base ? (Base >= Description->Minimum) && (Base <= Description->Maximum) + : (RangeStart >= Description->Minimum) && + (RangeEnd <= (ULONG)(Description->Maximum + Description->Length - 1)); + + if (Match) + { + if (Information) + *Information = Description->Information; + if (Length) + *Length = Description->Length; + if (WriteOrder) + *WriteOrder = LogDevice->Alternatives->IoIndex; + + return TRUE; + } + } + + return FALSE; +} + +CODE_SEG("PAGE") +BOOLEAN +FindIrqDescriptor( + _In_ PISAPNP_LOGICAL_DEVICE LogDevice, + _In_ ULONG Vector, + _Out_opt_ PUCHAR WriteOrder) +{ + ULONG i, j; + PISAPNP_IRQ_DESCRIPTION Description; + + PAGED_CODE(); + + for (i = 0; i < RTL_NUMBER_OF(LogDevice->Irq); i++) + { + Description = &LogDevice->Irq[i].Description; + + for (j = 0; j < RTL_BITS_OF(Description->Mask); j++) + { + if (Description->Mask & (1 << j)) + { + if (j == Vector) + { + if (WriteOrder) + *WriteOrder = LogDevice->Irq[i].Index; + + return TRUE; + } + } + } + } + + if (!LogDevice->Alternatives) + return FALSE; + + for (i = 0; i < LogDevice->Alternatives->Count; i++) + { + Description = &LogDevice->Alternatives->Irq[i]; + + for (j = 0; j < RTL_BITS_OF(Description->Mask); j++) + { + if (Description->Mask & (1 << j)) + { + if (j == Vector) + { + if (WriteOrder) + *WriteOrder = LogDevice->Alternatives->IrqIndex; + + return TRUE; + } + } + } + } + + return FALSE; +} + +CODE_SEG("PAGE") +BOOLEAN +FindDmaDescriptor( + _In_ PISAPNP_LOGICAL_DEVICE LogDevice, + _In_ ULONG Channel, + _Out_opt_ PUCHAR WriteOrder) +{ + ULONG i, j; + PISAPNP_DMA_DESCRIPTION Description; + + PAGED_CODE(); + + for (i = 0; i < RTL_NUMBER_OF(LogDevice->Dma); i++) + { + Description = &LogDevice->Dma[i].Description; + + for (j = 0; j < RTL_BITS_OF(Description->Mask); j++) + { + if (Description->Mask & (1 << j)) + { + if (j == Channel) + { + if (WriteOrder) + *WriteOrder = LogDevice->Dma[i].Index; + + return TRUE; + } + } + } + } + + if (!LogDevice->Alternatives) + return FALSE; + + for (i = 0; i < LogDevice->Alternatives->Count; i++) + { + Description = &LogDevice->Alternatives->Dma[i]; + + for (j = 0; j < RTL_BITS_OF(Description->Mask); j++) + { + if (Description->Mask & (1 << j)) + { + if (j == Channel) + { + if (WriteOrder) + *WriteOrder = LogDevice->Alternatives->DmaIndex; + + return TRUE; + } + } + } + } + + return FALSE; +} + +CODE_SEG("PAGE") +BOOLEAN +FindMemoryDescriptor( + _In_ PISAPNP_LOGICAL_DEVICE LogDevice, + _In_ ULONG RangeStart, + _In_ ULONG RangeEnd, + _Out_opt_ PBOOLEAN Memory32, + _Out_opt_ PUCHAR Information, + _Out_opt_ PUCHAR WriteOrder) +{ + ULONG i; + PISAPNP_MEMRANGE_DESCRIPTION Description; + PISAPNP_MEMRANGE32_DESCRIPTION Description32; + + PAGED_CODE(); + + for (i = 0; i < RTL_NUMBER_OF(LogDevice->MemRange); i++) + { + Description = &LogDevice->MemRange[i].Description; + + if ((RangeStart >= (ULONG)(Description->Minimum << 8)) && + (RangeEnd <= (ULONG)((Description->Maximum << 8) + (Description->Length << 8) - 1))) + { + if (Memory32) + *Memory32 = FALSE; + if (Information) + *Information = Description->Information; + if (WriteOrder) + *WriteOrder = LogDevice->MemRange[i].Index; + + return TRUE; + } + } + for (i = 0; i < RTL_NUMBER_OF(LogDevice->MemRange32); i++) + { + Description32 = &LogDevice->MemRange32[i].Description; + + if ((RangeStart >= Description32->Minimum) && + (RangeEnd <= (Description32->Maximum + Description32->Length - 1))) + { + if (Memory32) + *Memory32 = TRUE; + if (Information) + *Information = Description32->Information; + if (WriteOrder) + *WriteOrder = LogDevice->MemRange32[i].Index; + + return TRUE; + } + } + + if (!LogDevice->Alternatives) + return FALSE; + + for (i = 0; i < LogDevice->Alternatives->Count; i++) + { + Description = &LogDevice->Alternatives->MemRange[i]; + + if ((RangeStart >= (ULONG)(Description->Minimum << 8)) && + (RangeEnd <= (ULONG)((Description->Maximum << 8) + (Description->Length << 8) - 1))) + { + if (Memory32) + *Memory32 = FALSE; + if (Information) + *Information = Description->Information; + if (WriteOrder) + *WriteOrder = LogDevice->Alternatives->MemRangeIndex; + + return TRUE; + } + } + for (i = 0; i < LogDevice->Alternatives->Count; i++) + { + Description32 = &LogDevice->Alternatives->MemRange32[i]; + + if ((RangeStart >= Description32->Minimum) && + (RangeEnd <= (Description32->Maximum + Description32->Length - 1))) + { + if (Memory32) + *Memory32 = TRUE; + if (Information) + *Information = Description32->Information; + if (WriteOrder) + *WriteOrder = LogDevice->Alternatives->MemRange32Index; + + return TRUE; + } + } + + return FALSE; +} + static CODE_SEG("PAGE") NTSTATUS @@ -205,12 +790,16 @@ IsaPnpCreateLogicalDeviceResources( { PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice; ULONG ResourceCount = 0; + UCHAR Information; ULONG ListSize, i; PCM_RESOURCE_LIST ResourceList; PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; PAGED_CODE(); + if (!(LogDev->Flags & ISAPNP_HAS_RESOURCES)) + return STATUS_SUCCESS; + /* Count number of required resources */ for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++) { @@ -233,6 +822,20 @@ IsaPnpCreateLogicalDeviceResources( else break; } + for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange); i++) + { + if (LogDev->MemRange[i].CurrentBase) + ResourceCount++; + else + break; + } + for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange32); i++) + { + if (LogDev->MemRange32[i].CurrentBase) + ResourceCount++; + else + break; + } if (ResourceCount == 0) return STATUS_SUCCESS; @@ -253,17 +856,31 @@ IsaPnpCreateLogicalDeviceResources( ResourceCount = 0; for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++) { + ULONG CurrentLength; + if (!LogDev->Io[i].CurrentBase) break; + if (!FindIoDescriptor(LogDev, + LogDev->Io[i].CurrentBase, + 0, + 0, + &Information, + &CurrentLength, + NULL)) + { + goto InvalidBiosResources; + } + Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++]; Descriptor->Type = CmResourceTypePort; Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; - if (LogDev->Io[i].Description.Information & 0x1) - Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE; + Descriptor->Flags = CM_RESOURCE_PORT_IO; + if (Information & 0x1) + Descriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE; else - Descriptor->Flags = CM_RESOURCE_PORT_10_BIT_DECODE; - Descriptor->u.Port.Length = LogDev->Io[i].Description.Length; + Descriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE; + Descriptor->u.Port.Length = CurrentLength; Descriptor->u.Port.Start.LowPart = LogDev->Io[i].CurrentBase; } for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++) @@ -271,6 +888,9 @@ IsaPnpCreateLogicalDeviceResources( if (!LogDev->Irq[i].CurrentNo) break; + if (!FindIrqDescriptor(LogDev, LogDev->Irq[i].CurrentNo, NULL)) + goto InvalidBiosResources; + Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++]; Descriptor->Type = CmResourceTypeInterrupt; Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; @@ -280,38 +900,85 @@ IsaPnpCreateLogicalDeviceResources( Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED; Descriptor->u.Interrupt.Level = LogDev->Irq[i].CurrentNo; Descriptor->u.Interrupt.Vector = LogDev->Irq[i].CurrentNo; - Descriptor->u.Interrupt.Affinity = -1; + Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF; } for (i = 0; i < RTL_NUMBER_OF(LogDev->Dma); i++) { if (LogDev->Dma[i].CurrentChannel == 4) break; + if (!FindDmaDescriptor(LogDev, LogDev->Dma[i].CurrentChannel, NULL)) + goto InvalidBiosResources; + Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++]; Descriptor->Type = CmResourceTypeDma; Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; - switch (LogDev->Dma[i].Description.Information & 0x3) - { - case 0x0: Descriptor->Flags |= CM_RESOURCE_DMA_8; break; - case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_8 | CM_RESOURCE_DMA_16; break; - case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_16; break; - default: break; - } - if (LogDev->Dma[i].Description.Information & 0x4) - Descriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER; - switch ((LogDev->Dma[i].Description.Information >> 5) & 0x3) - { - case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_A; break; - case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_B; break; - case 0x3: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_F; break; - default: break; - } + Descriptor->Flags = CM_RESOURCE_DMA_8; /* Ignore information byte for compatibility */ Descriptor->u.Dma.Channel = LogDev->Dma[i].CurrentChannel; } + for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange); i++) + { + if (!LogDev->MemRange[i].CurrentBase) + break; + + if (!FindMemoryDescriptor(LogDev, + LogDev->MemRange[i].CurrentBase, + LogDev->MemRange[i].CurrentLength, + NULL, + &Information, + NULL)) + { + goto InvalidBiosResources; + } + + Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++]; + Descriptor->Type = CmResourceTypeMemory; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_MEMORY_24; + if ((Information & 0x40) || !(Information & 0x01)) + Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + Descriptor->u.Memory.Length = LogDev->MemRange[i].Description.Length; + Descriptor->u.Memory.Start.QuadPart = LogDev->MemRange[i].CurrentBase; + } + for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange32); i++) + { + if (!LogDev->MemRange32[i].CurrentBase) + break; + + if (!FindMemoryDescriptor(LogDev, + LogDev->MemRange32[i].CurrentBase, + LogDev->MemRange32[i].CurrentLength, + NULL, + &Information, + NULL)) + { + goto InvalidBiosResources; + } + + Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++]; + Descriptor->Type = CmResourceTypeMemory; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_MEMORY_24; + if ((Information & 0x40) || !(Information & 0x01)) + Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY; + else + Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE; + Descriptor->u.Memory.Length = LogDev->MemRange32[i].Description.Length; + Descriptor->u.Memory.Start.QuadPart = LogDev->MemRange32[i].CurrentBase; + } PdoExt->ResourceList = ResourceList; PdoExt->ResourceListSize = ListSize; return STATUS_SUCCESS; + +InvalidBiosResources: + DPRINT("Invalid boot resources! (CSN %u, LDN %u)\n", LogDev->CSN, LogDev->LDN); + + LogDev->Flags &= ~ISAPNP_HAS_RESOURCES; + ExFreePoolWithTag(ResourceList, TAG_ISAPNP); + return STATUS_SUCCESS; } _Dispatch_type_(IRP_MJ_CREATE) @@ -544,14 +1211,16 @@ IsaPnpCreateReadPortDOResources( ResourceList->List[0].PartialResourceList.Revision = 1; ResourceList->List[0].PartialResourceList.Count = RTL_NUMBER_OF(Ports); + Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[0]; for (i = 0; i < RTL_NUMBER_OF(Ports); i++) { - Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i]; Descriptor->Type = CmResourceTypePort; Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE; Descriptor->u.Port.Length = 0x01; Descriptor->u.Port.Start.LowPart = Ports[i]; + + Descriptor++; } PdoExt->ResourceList = ResourceList; diff --git a/drivers/bus/isapnp/isapnp.h b/drivers/bus/isapnp/isapnp.h index 3ba3e5032ac..00b82cb104b 100644 --- a/drivers/bus/isapnp/isapnp.h +++ b/drivers/bus/isapnp/isapnp.h @@ -279,6 +279,41 @@ HasMemory32Alternatives( /* isapnp.c */ +CODE_SEG("PAGE") +BOOLEAN +FindIoDescriptor( + _In_ PISAPNP_LOGICAL_DEVICE LogDevice, + _In_opt_ ULONG Base, + _In_ ULONG RangeStart, + _In_ ULONG RangeEnd, + _Out_opt_ PUCHAR Information, + _Out_opt_ PULONG Length, + _Out_opt_ PUCHAR WriteOrder); + +CODE_SEG("PAGE") +BOOLEAN +FindIrqDescriptor( + _In_ PISAPNP_LOGICAL_DEVICE LogDevice, + _In_ ULONG Vector, + _Out_opt_ PUCHAR WriteOrder); + +CODE_SEG("PAGE") +BOOLEAN +FindDmaDescriptor( + _In_ PISAPNP_LOGICAL_DEVICE LogDevice, + _In_ ULONG Channel, + _Out_opt_ PUCHAR WriteOrder); + +CODE_SEG("PAGE") +BOOLEAN +FindMemoryDescriptor( + _In_ PISAPNP_LOGICAL_DEVICE LogDevice, + _In_ ULONG RangeStart, + _In_ ULONG RangeEnd, + _Out_opt_ PBOOLEAN Memory32, + _Out_opt_ PUCHAR Information, + _Out_opt_ PUCHAR WriteOrder); + CODE_SEG("PAGE") NTSTATUS IsaPnpCreateReadPortDORequirements(