https://git.reactos.org/?p=reactos.git;a=commitdiff;h=8ed43b69073f47c25bb1c…
commit 8ed43b69073f47c25bb1c2ff644a3dc948f017bc
Author: Dmitry Borisov <di.sean(a)protonmail.com>
AuthorDate: Sat Mar 20 20:51:29 2021 +0600
Commit: Dmitry Borisov <di.sean(a)protonmail.com>
CommitDate: Sun Jun 20 19:24:31 2021 +0600
[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 | 887 ++++++++++++++++++++++++++++++++++++++------
drivers/bus/isapnp/isapnp.h | 35 ++
2 files changed, 813 insertions(+), 109 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 <search.h>
+
#define NDEBUG
#include <debug.h>
@@ -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;
+
+ 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;
+
+ 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;
- IrqData[i] = LogDev->Irq[i].Description.Mask;
- RtlInitializeBitMap(&IrqBitmap[i], &IrqData[i], 16);
- ResourceCount += RtlNumberOfSetBits(&IrqBitmap[i]);
+ ResourceCount++;
+ }
+ for (i = 0; i < RTL_NUMBER_OF(LogDev->MemRange32); i++)
+ {
+ if (!LogDev->MemRange32[i].Description.Length)
+ continue;
- if (LogDev->Irq[i].Description.Information & 0x4)
+ 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))
+ {
+ 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))
{
- /* Add room for level sensitive */
- ResourceCount += RtlNumberOfSetBits(&IrqBitmap[i]);
+ 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)
+ 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))
{
- 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;
+ goto InvalidBiosResources;
}
- if (LogDev->Dma[i].Description.Information & 0x4)
- Descriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER;
- switch ((LogDev->Dma[i].Description.Information >> 5) & 0x3)
+
+ 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))
{
- 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;
+ goto InvalidBiosResources;
}
- Descriptor->u.Dma.Channel = LogDev->Dma[i].CurrentChannel;
+
+ 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(