https://git.reactos.org/?p=reactos.git;a=commitdiff;h=ca42de9c314c5c97e212d…
commit ca42de9c314c5c97e212dc08e6a2e2df15324151
Author: Dmitry Borisov <di.sean(a)protonmail.com>
AuthorDate: Sat Mar 20 20:50:34 2021 +0600
Commit: Dmitry Borisov <di.sean(a)protonmail.com>
CommitDate: Sun Jun 20 19:24:31 2021 +0600
[ISAPNP] Rewrite the tag parser
- Support all resource descriptors.
- Optimize card identification.
- Detect cards that is no longer present on the bus.
- Deactivate cards after the identification phase; they will be activated
by start device IRP.
- Provide a device description and compatible IDs to the device manager.
- Prevent duplicate IDs across multiple logical devices.
- Suppress warning about the usage of literals in port addresses.
---
drivers/bus/isapnp/hardware.c | 868 +++++++++++++++++++++++++++++++++++++-----
drivers/bus/isapnp/isapnp.c | 8 +-
drivers/bus/isapnp/isapnp.h | 120 +++++-
drivers/bus/isapnp/isapnphw.h | 72 ++--
drivers/bus/isapnp/pdo.c | 194 +++++++++-
5 files changed, 1114 insertions(+), 148 deletions(-)
diff --git a/drivers/bus/isapnp/hardware.c b/drivers/bus/isapnp/hardware.c
index 6673e200194..9dae1c66eb6 100644
--- a/drivers/bus/isapnp/hardware.c
+++ b/drivers/bus/isapnp/hardware.c
@@ -4,6 +4,7 @@
* PURPOSE: Hardware support code
* COPYRIGHT: Copyright 2010 Cameron Gutman <cameron.gutman(a)reactos.org>
* Copyright 2020 Hervé Poussineau <hpoussin(a)reactos.org>
+ * Copyright 2021 Dmitry Borisov <di.sean(a)protonmail.com>
*/
#include "isapnp.h"
@@ -11,6 +12,17 @@
#define NDEBUG
#include <debug.h>
+#ifdef _MSC_VER
+#pragma warning(disable:28138) /* ISA bus always uses hardcoded port addresses */
+#endif
+
+typedef enum
+{
+ dfNotStarted,
+ dfStarted,
+ dfDone
+} DEPEDENT_FUNCTION_STATE;
+
static
inline
VOID
@@ -291,6 +303,24 @@ Peek(
}
}
+static
+CODE_SEG("PAGE")
+VOID
+PeekCached(
+ _In_reads_bytes_(Length) PUCHAR ResourceData,
+ _Out_writes_bytes_all_(Length) PVOID Buffer,
+ _In_ USHORT Length)
+{
+ PUCHAR Dest = Buffer;
+
+ PAGED_CODE();
+
+ while (Length--)
+ {
+ *Dest++ = *ResourceData++;
+ }
+}
+
static
CODE_SEG("PAGE")
UCHAR
@@ -318,24 +348,48 @@ IsaPnpChecksum(
static
CODE_SEG("PAGE")
-BOOLEAN
+VOID
+IsaPnpExtractAscii(
+ _Out_writes_all_(3) PUCHAR Buffer,
+ _In_ USHORT CompressedData)
+{
+ PAGED_CODE();
+
+ Buffer[0] = ((CompressedData >> 2) & 0x1F) + 'A' - 1;
+ Buffer[1] = (((CompressedData & 0x3) << 3) | ((CompressedData >> 13)
& 0x7)) + 'A' - 1;
+ Buffer[2] = ((CompressedData >> 8) & 0x1F) + 'A' - 1;
+}
+
+static
+CODE_SEG("PAGE")
+NTSTATUS
ReadTags(
_In_ PUCHAR ReadDataPort,
- _In_ USHORT LogDev,
- _Inout_ PISAPNP_LOGICAL_DEVICE LogDevice)
+ _Out_writes_(ISAPNP_MAX_RESOURCEDATA) PUCHAR Buffer,
+ _In_ ULONG MaxLength,
+ _Out_ PUSHORT MaxLogDev)
{
- BOOLEAN res = FALSE;
- PVOID Buffer;
- USHORT Tag, TagLen, MaxLen;
- ULONG NumberOfIo = 0, NumberOfIrq = 0, NumberOfDma = 0;
-
PAGED_CODE();
- LogDev += 1;
+ *MaxLogDev = 0;
while (TRUE)
{
+ UCHAR Tag;
+ USHORT TagLen;
+
+ if (MaxLength < 1)
+ return STATUS_BUFFER_OVERFLOW;
+
Tag = PeekByte(ReadDataPort);
+ if (Tag == 0)
+ {
+ DPRINT("Invalid tag\n");
+ return STATUS_INVALID_PARAMETER_1;
+ }
+ *Buffer++ = Tag;
+ --MaxLength;
+
if (ISAPNP_IS_SMALL_TAG(Tag))
{
TagLen = ISAPNP_SMALL_TAG_LEN(Tag);
@@ -343,64 +397,623 @@ ReadTags(
}
else
{
- TagLen = PeekByte(ReadDataPort) + (PeekByte(ReadDataPort) << 8);
+ UCHAR Temp[2];
+
+ if (MaxLength < sizeof(Temp))
+ return STATUS_BUFFER_OVERFLOW;
+
+ Peek(ReadDataPort, &Temp, sizeof(Temp));
+ *Buffer++ = Temp[0];
+ *Buffer++ = Temp[1];
+ MaxLength -= sizeof(Temp);
+
+ TagLen = Temp[0] + (Temp[1] << 8);
Tag = ISAPNP_LARGE_TAG_NAME(Tag);
}
- if (Tag == ISAPNP_TAG_END)
- break;
- Buffer = NULL;
- if (Tag == ISAPNP_TAG_LOGDEVID)
- {
- MaxLen = sizeof(LogDevice->LogDevId);
- Buffer = &LogDevice->LogDevId;
- LogDev--;
- }
- else if (Tag == ISAPNP_TAG_IRQ && NumberOfIrq <
ARRAYSIZE(LogDevice->Irq))
- {
- MaxLen = sizeof(LogDevice->Irq[NumberOfIrq].Description);
- Buffer = &LogDevice->Irq[NumberOfIrq].Description;
- NumberOfIrq++;
- }
- else if (Tag == ISAPNP_TAG_IOPORT && NumberOfIo <
ARRAYSIZE(LogDevice->Io))
+ if (Tag == 0xFF && TagLen == 0xFFFF)
{
- MaxLen = sizeof(LogDevice->Io[NumberOfIo].Description);
- Buffer = &LogDevice->Io[NumberOfIo].Description;
- NumberOfIo++;
+ DPRINT("Invalid tag\n");
+ return STATUS_INVALID_PARAMETER_2;
}
- else if (Tag == ISAPNP_TAG_DMA && NumberOfDma <
ARRAYSIZE(LogDevice->Dma))
+
+ if (TagLen > MaxLength)
+ return STATUS_BUFFER_OVERFLOW;
+
+ Peek(ReadDataPort, Buffer, TagLen);
+ MaxLength -= TagLen;
+ Buffer += TagLen;
+
+ if (Tag == ISAPNP_TAG_LOGDEVID)
+ (*MaxLogDev)++;
+
+ if (Tag == ISAPNP_TAG_END)
+ break;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+VOID
+FreeLogicalDevice(
+ _In_ __drv_freesMem(Mem) PISAPNP_LOGICAL_DEVICE LogDevice)
+{
+ PLIST_ENTRY Entry;
+
+ PAGED_CODE();
+
+ if (LogDevice->FriendlyName)
+ ExFreePoolWithTag(LogDevice->FriendlyName, TAG_ISAPNP);
+
+ if (LogDevice->Alternatives)
+ ExFreePoolWithTag(LogDevice->Alternatives, TAG_ISAPNP);
+
+ Entry = LogDevice->CompatibleIdList.Flink;
+ while (Entry != &LogDevice->CompatibleIdList)
+ {
+ PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId =
+ CONTAINING_RECORD(Entry, ISAPNP_COMPATIBLE_ID_ENTRY, IdLink);
+
+ RemoveEntryList(&CompatibleId->IdLink);
+
+ Entry = Entry->Flink;
+
+ ExFreePoolWithTag(CompatibleId, TAG_ISAPNP);
+ }
+
+ ExFreePoolWithTag(LogDevice, TAG_ISAPNP);
+}
+
+static
+CODE_SEG("PAGE")
+NTSTATUS
+ParseTags(
+ _In_ PUCHAR ResourceData,
+ _In_ USHORT LogDevToParse,
+ _Inout_ PISAPNP_LOGICAL_DEVICE LogDevice)
+{
+ USHORT LogDev;
+ DEPEDENT_FUNCTION_STATE DfState = dfNotStarted;
+ PUCHAR IdStrPos = NULL;
+ USHORT IdStrLen = 0;
+ UCHAR NumberOfIo = 0,
+ NumberOfIrq = 0,
+ NumberOfDma = 0,
+ NumberOfMemRange = 0,
+ NumberOfMemRange32 = 0,
+ NumberOfDepedentSet = 0;
+
+ PAGED_CODE();
+
+ DPRINT("%s for CSN %u, LDN %u\n", __FUNCTION__, LogDevice->CSN,
LogDevice->LDN);
+
+ LogDev = LogDevToParse + 1;
+
+ while (TRUE)
+ {
+ UCHAR Tag;
+ USHORT TagLen;
+
+ Tag = *ResourceData++;
+
+ if (ISAPNP_IS_SMALL_TAG(Tag))
{
- MaxLen = sizeof(LogDevice->Dma[NumberOfDma].Description);
- Buffer = &LogDevice->Dma[NumberOfDma].Description;
- NumberOfDma++;
+ TagLen = ISAPNP_SMALL_TAG_LEN(Tag);
+ Tag = ISAPNP_SMALL_TAG_NAME(Tag);
}
- else if (LogDev == 0)
+ else
{
- DPRINT1("Found unknown tag 0x%x (len %d)\n", Tag, TagLen);
+ TagLen = *ResourceData++;
+ TagLen += *ResourceData++ << 8;
+
+ Tag = ISAPNP_LARGE_TAG_NAME(Tag);
}
- if (Buffer && LogDev == 0)
+ switch (Tag)
{
- res = TRUE;
- if (MaxLen > TagLen)
+ case ISAPNP_TAG_LOGDEVID:
{
- Peek(ReadDataPort, Buffer, TagLen);
+ ISAPNP_LOGDEVID Temp;
+
+ --LogDev;
+
+ if (LogDev != 0 ||
+ (TagLen > sizeof(ISAPNP_LOGDEVID) ||
+ TagLen < (sizeof(ISAPNP_LOGDEVID) - 1)))
+ {
+ goto SkipTag;
+ }
+
+ PeekCached(ResourceData, &Temp, TagLen);
+ ResourceData += TagLen;
+
+ DPRINT("Found tag 0x%X (len %u)\n"
+ " VendorId 0x%04X\n"
+ " ProdId 0x%04X\n",
+ Tag, TagLen,
+ Temp.VendorId,
+ Temp.ProdId);
+
+ IsaPnpExtractAscii(LogDevice->LogVendorId, Temp.VendorId);
+ LogDevice->LogProdId = RtlUshortByteSwap(Temp.ProdId);
+
+ break;
}
- else
+
+ case ISAPNP_TAG_COMPATDEVID:
{
- Peek(ReadDataPort, Buffer, MaxLen);
- Peek(ReadDataPort, NULL, TagLen - MaxLen);
+ ISAPNP_COMPATID Temp;
+ PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId;
+
+ if (LogDev != 0 || TagLen != sizeof(ISAPNP_COMPATID))
+ goto SkipTag;
+
+ CompatibleId = ExAllocatePoolWithTag(PagedPool,
+ sizeof(ISAPNP_COMPATIBLE_ID_ENTRY),
+ TAG_ISAPNP);
+ if (!CompatibleId)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ PeekCached(ResourceData, &Temp, TagLen);
+ ResourceData += TagLen;
+
+ DPRINT("Found tag 0x%X (len %u)\n"
+ " VendorId 0x%04X\n"
+ " ProdId 0x%04X\n",
+ Tag, TagLen,
+ Temp.VendorId,
+ Temp.ProdId);
+
+ IsaPnpExtractAscii(CompatibleId->VendorId, Temp.VendorId);
+ CompatibleId->ProdId = RtlUshortByteSwap(Temp.ProdId);
+
+ InsertTailList(&LogDevice->CompatibleIdList,
&CompatibleId->IdLink);
+
+ break;
}
- }
- else
- {
- /* We don't want to read informations on this
- * logical device, or we don't know the tag. */
- Peek(ReadDataPort, NULL, TagLen);
- }
- };
- return res;
+ case ISAPNP_TAG_IRQ:
+ {
+ PISAPNP_IRQ_DESCRIPTION Description;
+
+ if (LogDev != 0 ||
+ (TagLen > sizeof(ISAPNP_IRQ_DESCRIPTION) ||
+ TagLen < (sizeof(ISAPNP_IRQ_DESCRIPTION) - 1)) ||
+ NumberOfIrq >= RTL_NUMBER_OF(LogDevice->Irq))
+ {
+ goto SkipTag;
+ }
+
+ if (DfState == dfStarted)
+ {
+ if (NumberOfDepedentSet >= ISAPNP_MAX_ALTERNATIVES)
+ goto SkipTag;
+
+ Description =
&LogDevice->Alternatives->Irq[NumberOfDepedentSet];
+ }
+ else
+ {
+ Description = &LogDevice->Irq[NumberOfIrq].Description;
+
+ LogDevice->Irq[NumberOfIrq].Index = NumberOfIrq;
+ ++NumberOfIrq;
+ }
+
+ PeekCached(ResourceData, Description, TagLen);
+ ResourceData += TagLen;
+
+ if (TagLen == (sizeof(ISAPNP_IRQ_DESCRIPTION) - 1))
+ Description->Information = 0x01;
+
+ DPRINT("Found tag 0x%X (len %u)\n"
+ " Mask 0x%X\n"
+ " Information 0x%X\n",
+ Tag, TagLen,
+ Description->Mask,
+ Description->Information);
+
+ break;
+ }
+
+ case ISAPNP_TAG_DMA:
+ {
+ PISAPNP_DMA_DESCRIPTION Description;
+
+ if (LogDev != 0 || TagLen != sizeof(ISAPNP_DMA_DESCRIPTION) ||
+ NumberOfDma >= RTL_NUMBER_OF(LogDevice->Dma))
+ {
+ goto SkipTag;
+ }
+
+ if (DfState == dfStarted)
+ {
+ if (NumberOfDepedentSet >= ISAPNP_MAX_ALTERNATIVES)
+ goto SkipTag;
+
+ Description =
&LogDevice->Alternatives->Dma[NumberOfDepedentSet];
+ }
+ else
+ {
+ Description = &LogDevice->Dma[NumberOfDma].Description;
+
+ LogDevice->Dma[NumberOfDma].Index = NumberOfDma;
+ ++NumberOfDma;
+ }
+
+ PeekCached(ResourceData, Description, TagLen);
+ ResourceData += TagLen;
+
+ DPRINT("Found tag 0x%X (len %u)\n"
+ " Mask 0x%X\n"
+ " Information 0x%X\n",
+ Tag, TagLen,
+ Description->Mask,
+ Description->Information);
+
+ break;
+ }
+
+ case ISAPNP_TAG_STARTDEP:
+ {
+ if (LogDev != 0 || TagLen > 1 ||
+ NumberOfDepedentSet >= ISAPNP_MAX_ALTERNATIVES)
+ {
+ goto SkipTag;
+ }
+
+ if (DfState == dfNotStarted)
+ {
+ LogDevice->Alternatives = ExAllocatePoolZero(PagedPool,
+
sizeof(ISAPNP_ALTERNATIVES),
+ TAG_ISAPNP);
+ if (!LogDevice->Alternatives)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ DfState = dfStarted;
+ }
+ else if (DfState == dfStarted)
+ {
+ ++NumberOfDepedentSet;
+ }
+ else
+ {
+ goto SkipTag;
+ }
+
+ ++LogDevice->Alternatives->Count;
+
+ if (TagLen != 1)
+ {
+ LogDevice->Alternatives->Priority[NumberOfDepedentSet] = 1;
+ }
+ else
+ {
+ PeekCached(ResourceData,
+
&LogDevice->Alternatives->Priority[NumberOfDepedentSet],
+ TagLen);
+ ResourceData += TagLen;
+ }
+
+ DPRINT("*** Start depedent set %u, priority %u ***\n",
+ NumberOfDepedentSet,
+ LogDevice->Alternatives->Priority[NumberOfDepedentSet]);
+
+ break;
+ }
+
+ case ISAPNP_TAG_ENDDEP:
+ {
+ if (LogDev != 0 || DfState != dfStarted)
+ goto SkipTag;
+
+ DfState = dfDone;
+
+ ResourceData += TagLen;
+
+ if (HasIoAlternatives(LogDevice->Alternatives))
+ LogDevice->Alternatives->IoIndex = NumberOfIo++;
+ if (HasIrqAlternatives(LogDevice->Alternatives))
+ LogDevice->Alternatives->IrqIndex = NumberOfIrq++;
+ if (HasDmaAlternatives(LogDevice->Alternatives))
+ LogDevice->Alternatives->DmaIndex = NumberOfDma++;
+ if (HasMemoryAlternatives(LogDevice->Alternatives))
+ LogDevice->Alternatives->MemRangeIndex = NumberOfMemRange++;
+ if (HasMemory32Alternatives(LogDevice->Alternatives))
+ LogDevice->Alternatives->MemRange32Index =
NumberOfMemRange32++;
+
+ DPRINT("*** End of depedent set ***\n");
+
+ break;
+ }
+
+ case ISAPNP_TAG_IOPORT:
+ {
+ PISAPNP_IO_DESCRIPTION Description;
+
+ if (LogDev != 0 || TagLen != sizeof(ISAPNP_IO_DESCRIPTION) ||
+ NumberOfIo >= RTL_NUMBER_OF(LogDevice->Io))
+ {
+ goto SkipTag;
+ }
+
+ if (DfState == dfStarted)
+ {
+ if (NumberOfDepedentSet >= ISAPNP_MAX_ALTERNATIVES)
+ goto SkipTag;
+
+ Description =
&LogDevice->Alternatives->Io[NumberOfDepedentSet];
+ }
+ else
+ {
+ Description = &LogDevice->Io[NumberOfIo].Description;
+
+ LogDevice->Io[NumberOfIo].Index = NumberOfIo;
+ ++NumberOfIo;
+ }
+
+ PeekCached(ResourceData, Description, TagLen);
+ ResourceData += TagLen;
+
+ DPRINT("Found tag 0x%X (len %u)\n"
+ " Information 0x%X\n"
+ " Minimum 0x%X\n"
+ " Maximum 0x%X\n"
+ " Alignment 0x%X\n"
+ " Length 0x%X\n",
+ Tag, TagLen,
+ Description->Information,
+ Description->Minimum,
+ Description->Maximum,
+ Description->Alignment,
+ Description->Length);
+
+ break;
+ }
+
+ case ISAPNP_TAG_FIXEDIO:
+ {
+ ISAPNP_FIXED_IO_DESCRIPTION Temp;
+ PISAPNP_IO_DESCRIPTION Description;
+
+ if (LogDev != 0 || TagLen != sizeof(ISAPNP_FIXED_IO_DESCRIPTION) ||
+ NumberOfIo >= RTL_NUMBER_OF(LogDevice->Io))
+ {
+ goto SkipTag;
+ }
+
+ if (DfState == dfStarted)
+ {
+ if (NumberOfDepedentSet >= ISAPNP_MAX_ALTERNATIVES)
+ goto SkipTag;
+
+ Description =
&LogDevice->Alternatives->Io[NumberOfDepedentSet];
+ }
+ else
+ {
+ Description = &LogDevice->Io[NumberOfIo].Description;
+
+ LogDevice->Io[NumberOfIo].Index = NumberOfIo;
+ ++NumberOfIo;
+ }
+
+ PeekCached(ResourceData, &Temp, TagLen);
+ ResourceData += TagLen;
+
+ Description->Information = 0;
+ Description->Minimum =
+ Description->Maximum = Temp.IoBase;
+ Description->Alignment = 1;
+ Description->Length = Temp.Length;
+
+ DPRINT("Found tag 0x%X (len %u)\n"
+ " IoBase 0x%X\n"
+ " Length 0x%X\n",
+ Tag, TagLen,
+ Temp.IoBase,
+ Temp.Length);
+
+ break;
+ }
+
+ case ISAPNP_TAG_END:
+ {
+ if (IdStrPos)
+ {
+ PSTR End;
+
+ LogDevice->FriendlyName = ExAllocatePoolWithTag(PagedPool,
+ IdStrLen +
sizeof(ANSI_NULL),
+ TAG_ISAPNP);
+ if (!LogDevice->FriendlyName)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ PeekCached(IdStrPos, LogDevice->FriendlyName, IdStrLen);
+
+ End = LogDevice->FriendlyName + IdStrLen - 1;
+ while (End > LogDevice->FriendlyName && *End == '
')
+ {
+ --End;
+ }
+ *++End = ANSI_NULL;
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ case ISAPNP_TAG_MEMRANGE:
+ {
+ PISAPNP_MEMRANGE_DESCRIPTION Description;
+
+ if (LogDev != 0 || TagLen != sizeof(ISAPNP_MEMRANGE_DESCRIPTION) ||
+ NumberOfMemRange >= RTL_NUMBER_OF(LogDevice->MemRange))
+ {
+ goto SkipTag;
+ }
+
+ if (DfState == dfStarted)
+ {
+ if (NumberOfDepedentSet >= ISAPNP_MAX_ALTERNATIVES)
+ goto SkipTag;
+
+ Description =
&LogDevice->Alternatives->MemRange[NumberOfDepedentSet];
+ }
+ else
+ {
+ Description =
&LogDevice->MemRange[NumberOfMemRange].Description;
+
+ LogDevice->MemRange[NumberOfMemRange].Index = NumberOfMemRange;
+ ++NumberOfMemRange;
+ }
+
+ PeekCached(ResourceData, Description, TagLen);
+ ResourceData += TagLen;
+
+ DPRINT("Found tag 0x%X (len %u)\n"
+ " Information 0x%X\n"
+ " Minimum 0x%X\n"
+ " Maximum 0x%X\n"
+ " Alignment 0x%X\n"
+ " Length 0x%X\n",
+ Tag, TagLen,
+ Description->Information,
+ Description->Minimum,
+ Description->Maximum,
+ Description->Alignment,
+ Description->Length);
+
+ break;
+ }
+
+ case ISAPNP_TAG_ANSISTR:
+ {
+ /* If logical device identifier is not supplied, use card identifier */
+ if (LogDev == LogDevToParse + 1 || LogDev == 0)
+ {
+ IdStrPos = ResourceData;
+ IdStrLen = TagLen;
+
+ ResourceData += TagLen;
+
+ DPRINT("Found tag 0x%X (len %u)\n"
+ " '%.*s'\n",
+ Tag, TagLen,
+ IdStrLen,
+ IdStrPos);
+ }
+ else
+ {
+ goto SkipTag;
+ }
+
+ break;
+ }
+
+ case ISAPNP_TAG_MEM32RANGE:
+ {
+ PISAPNP_MEMRANGE32_DESCRIPTION Description;
+
+ if (LogDev != 0 || TagLen != sizeof(ISAPNP_MEMRANGE32_DESCRIPTION) ||
+ NumberOfMemRange32 >= RTL_NUMBER_OF(LogDevice->MemRange32))
+ {
+ goto SkipTag;
+ }
+
+ if (DfState == dfStarted)
+ {
+ if (NumberOfDepedentSet >= ISAPNP_MAX_ALTERNATIVES)
+ goto SkipTag;
+
+ Description =
&LogDevice->Alternatives->MemRange32[NumberOfDepedentSet];
+ }
+ else
+ {
+ Description =
&LogDevice->MemRange32[NumberOfMemRange32].Description;
+
+ LogDevice->MemRange32[NumberOfMemRange32].Index =
NumberOfMemRange32;
+ ++NumberOfMemRange32;
+ }
+
+ PeekCached(ResourceData, Description, TagLen);
+ ResourceData += TagLen;
+
+ DPRINT("Found tag 0x%X (len %u)\n"
+ " Information 0x%X\n"
+ " Minimum 0x%08lX\n"
+ " Maximum 0x%08lX\n"
+ " Alignment 0x%08lX\n"
+ " Length 0x%08lX\n",
+ Tag, TagLen,
+ Description->Information,
+ Description->Minimum,
+ Description->Maximum,
+ Description->Alignment,
+ Description->Length);
+
+ break;
+ }
+
+ case ISAPNP_TAG_FIXEDMEM32RANGE:
+ {
+ ISAPNP_FIXEDMEMRANGE_DESCRIPTION Temp;
+ PISAPNP_MEMRANGE32_DESCRIPTION Description;
+
+ if (LogDev != 0 || TagLen != sizeof(ISAPNP_FIXEDMEMRANGE_DESCRIPTION) ||
+ NumberOfMemRange32 >= RTL_NUMBER_OF(LogDevice->MemRange32))
+ {
+ goto SkipTag;
+ }
+
+ if (DfState == dfStarted)
+ {
+ if (NumberOfDepedentSet >= ISAPNP_MAX_ALTERNATIVES)
+ goto SkipTag;
+
+ Description =
&LogDevice->Alternatives->MemRange32[NumberOfDepedentSet];
+ }
+ else
+ {
+ Description =
&LogDevice->MemRange32[NumberOfMemRange32].Description;
+
+ LogDevice->MemRange32[NumberOfMemRange32].Index =
NumberOfMemRange32;
+ ++NumberOfMemRange32;
+ }
+
+ PeekCached(ResourceData, &Temp, TagLen);
+ ResourceData += TagLen;
+
+ Description->Information = Temp.Information;
+ Description->Minimum =
+ Description->Maximum = Temp.MemoryBase;
+ Description->Alignment = 1;
+ Description->Length = Temp.Length;
+
+ DPRINT("Found tag 0x%X (len %u)\n"
+ " Information 0x%X\n"
+ " MemoryBase 0x%08lX\n"
+ " Length 0x%08lX\n",
+ Tag, TagLen,
+ Temp.Information,
+ Temp.MemoryBase,
+ Temp.Length);
+
+ break;
+ }
+
+SkipTag:
+ default:
+ {
+ if (LogDev == 0)
+ DPRINT("Found unknown tag 0x%X (len %u)\n", Tag, TagLen);
+
+ /* We don't want to read informations on this
+ * logical device, or we don't know the tag. */
+ ResourceData += TagLen;
+ break;
+ }
+ }
+ }
}
static
@@ -532,54 +1145,127 @@ DeviceActivation(
WaitForKey();
}
-static
+_Requires_lock_held_(FdoExt->DeviceSyncEvent)
CODE_SEG("PAGE")
NTSTATUS
-ProbeIsaPnpBus(
+IsaHwFillDeviceList(
_In_ PISAPNP_FDO_EXTENSION FdoExt)
{
PISAPNP_LOGICAL_DEVICE LogDevice;
- ISAPNP_IDENTIFIER Identifier;
- USHORT Csn;
- USHORT LogDev;
+ UCHAR Csn;
ULONG i;
+ PLIST_ENTRY Entry;
+ PUCHAR ResourceData;
PAGED_CODE();
ASSERT(FdoExt->ReadDataPort);
- for (Csn = 1; Csn <= 0xFF; Csn++)
+ DPRINT("%s for read port 0x%p\n", __FUNCTION__, FdoExt->ReadDataPort);
+
+ ResourceData = ExAllocatePoolWithTag(PagedPool, ISAPNP_MAX_RESOURCEDATA, TAG_ISAPNP);
+ if (!ResourceData)
+ {
+ DPRINT1("Failed to allocate memory for cache data\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ for (Entry = FdoExt->DeviceListHead.Flink;
+ Entry != &FdoExt->DeviceListHead;
+ Entry = Entry->Flink)
+ {
+ LogDevice = CONTAINING_RECORD(Entry, ISAPNP_LOGICAL_DEVICE, DeviceLink);
+
+ LogDevice->Flags &= ~ISAPNP_PRESENT;
+ }
+
+ WaitForKey();
+ SendKey();
+
+ for (Csn = 1; Csn <= FdoExt->Cards; Csn++)
{
- for (LogDev = 0; LogDev <= 0xFF; LogDev++)
+ NTSTATUS Status;
+ UCHAR TempId[3], LogDev;
+ ISAPNP_IDENTIFIER Identifier;
+ USHORT MaxLogDev;
+
+ Wake(Csn);
+
+ Peek(FdoExt->ReadDataPort, &Identifier, sizeof(Identifier));
+
+ IsaPnpExtractAscii(TempId, Identifier.VendorId);
+ Identifier.ProdId = RtlUshortByteSwap(Identifier.ProdId);
+
+ Status = ReadTags(FdoExt->ReadDataPort, ResourceData, ISAPNP_MAX_RESOURCEDATA,
&MaxLogDev);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to read tags with status 0x%08lx, CSN %u\n",
Status, Csn);
+ continue;
+ }
+
+ DPRINT("Detected ISA PnP device - VID: '%.3s' PID: 0x%04x SN:
0x%08lX\n",
+ TempId, Identifier.ProdId, Identifier.Serial);
+
+ for (LogDev = 0; LogDev < MaxLogDev; LogDev++)
{
+ BOOLEAN IsAlreadyEnumerated = FALSE;
+
+ for (Entry = FdoExt->DeviceListHead.Flink;
+ Entry != &FdoExt->DeviceListHead;
+ Entry = Entry->Flink)
+ {
+ LogDevice = CONTAINING_RECORD(Entry, ISAPNP_LOGICAL_DEVICE, DeviceLink);
+
+ /* This logical device has already been enumerated */
+ if ((LogDevice->SerialNumber == Identifier.Serial) &&
+ (RtlCompareMemory(LogDevice->VendorId, TempId, 3) == 3) &&
+ (LogDevice->ProdId == Identifier.ProdId) &&
+ (LogDevice->LDN == LogDev))
+ {
+ LogDevice->Flags |= ISAPNP_PRESENT;
+
+ /* Assign a new CSN */
+ LogDevice->CSN = Csn;
+
+ if (LogDevice->Pdo)
+ {
+ PISAPNP_PDO_EXTENSION PdoExt =
LogDevice->Pdo->DeviceExtension;
+
+ if (PdoExt->Common.State == dsStarted)
+ ActivateDevice(LogDev);
+ }
+
+ DPRINT("Skip CSN %u, LDN %u\n", LogDevice->CSN,
LogDevice->LDN);
+ IsAlreadyEnumerated = TRUE;
+ break;
+ }
+ }
+
+ if (IsAlreadyEnumerated)
+ continue;
+
LogDevice = ExAllocatePoolZero(NonPagedPool, sizeof(ISAPNP_LOGICAL_DEVICE),
TAG_ISAPNP);
if (!LogDevice)
- return STATUS_NO_MEMORY;
+ {
+ DPRINT1("Failed to allocate logical device!\n");
+ goto Deactivate;
+ }
+
+ InitializeListHead(&LogDevice->CompatibleIdList);
LogDevice->CSN = Csn;
LogDevice->LDN = LogDev;
- WaitForKey();
- SendKey();
- Wake(Csn);
-
- Peek(FdoExt->ReadDataPort, &Identifier, sizeof(Identifier));
-
- if (Identifier.VendorId & 0x80)
+ Status = ParseTags(ResourceData, LogDev, LogDevice);
+ if (!NT_SUCCESS(Status))
{
- ExFreePoolWithTag(LogDevice, TAG_ISAPNP);
- return STATUS_SUCCESS;
+ DPRINT1("Failed to parse tags with status 0x%08lx, CSN %u, LDN
%u\n",
+ Status, LogDevice->CSN, LogDevice->LDN);
+ FreeLogicalDevice(LogDevice);
+ goto Deactivate;
}
- if (!ReadTags(FdoExt->ReadDataPort, LogDev, LogDevice))
- break;
-
WriteLogicalDeviceNumber(LogDev);
- LogDevice->VendorId[0] = ((LogDevice->LogDevId.VendorId >> 2)
& 0x1f) + 'A' - 1,
- LogDevice->VendorId[1] = (((LogDevice->LogDevId.VendorId & 0x3)
<< 3) | ((LogDevice->LogDevId.VendorId >> 13) & 0x7)) + 'A' -
1,
- LogDevice->VendorId[2] = ((LogDevice->LogDevId.VendorId >> 8)
& 0x1f) + 'A' - 1,
- LogDevice->ProdId = RtlUshortByteSwap(LogDevice->LogDevId.ProdId);
- LogDevice->SerialNumber = Identifier.Serial;
for (i = 0; i < ARRAYSIZE(LogDevice->Io); i++)
LogDevice->Io[i].CurrentBase = ReadIoBase(FdoExt->ReadDataPort, i);
for (i = 0; i < ARRAYSIZE(LogDevice->Irq); i++)
@@ -592,27 +1278,37 @@ ProbeIsaPnpBus(
LogDevice->Dma[i].CurrentChannel =
ReadDmaChannel(FdoExt->ReadDataPort, i);
}
- DPRINT1("Detected ISA PnP device - VID: '%3s' PID: 0x%x SN:
0x%08x IoBase: 0x%x IRQ:0x%x\n",
- LogDevice->VendorId, LogDevice->ProdId,
LogDevice->SerialNumber, LogDevice->Io[0].CurrentBase,
LogDevice->Irq[0].CurrentNo);
+ IsaPnpExtractAscii(LogDevice->VendorId, Identifier.VendorId);
+ LogDevice->ProdId = Identifier.ProdId;
+ LogDevice->SerialNumber = Identifier.Serial;
- WaitForKey();
+ if (MaxLogDev > 1)
+ LogDevice->Flags |= ISAPNP_HAS_MULTIPLE_LOGDEVS;
+
+ LogDevice->Flags |= ISAPNP_PRESENT;
InsertTailList(&FdoExt->DeviceListHead,
&LogDevice->DeviceLink);
FdoExt->DeviceCount++;
+
+ /* Now we wait for the start device IRP */
+Deactivate:
+ DeactivateDevice(LogDev);
}
}
+ ExFreePoolWithTag(ResourceData, TAG_ISAPNP);
+
return STATUS_SUCCESS;
}
CODE_SEG("PAGE")
-NTSTATUS
+ULONG
IsaHwTryReadDataPort(
_In_ PUCHAR ReadDataPort)
{
PAGED_CODE();
- return TryIsolate(ReadDataPort) > 0 ? STATUS_SUCCESS :
STATUS_INSUFFICIENT_RESOURCES;
+ return TryIsolate(ReadDataPort);
}
_IRQL_requires_max_(DISPATCH_LEVEL)
@@ -636,13 +1332,3 @@ IsaHwDeactivateDevice(
return STATUS_SUCCESS;
}
-
-CODE_SEG("PAGE")
-NTSTATUS
-IsaHwFillDeviceList(
- _In_ PISAPNP_FDO_EXTENSION FdoExt)
-{
- PAGED_CODE();
-
- return ProbeIsaPnpBus(FdoExt);
-}
diff --git a/drivers/bus/isapnp/isapnp.c b/drivers/bus/isapnp/isapnp.c
index 41f52c9aed6..842929ee0ce 100644
--- a/drivers/bus/isapnp/isapnp.c
+++ b/drivers/bus/isapnp/isapnp.c
@@ -676,11 +676,11 @@ IsaPnpFillDeviceRelations(
DPRINT("Rescan ISA PnP bus\n");
/* Run the isolation protocol */
- if (NT_SUCCESS(IsaHwTryReadDataPort(FdoExt->ReadDataPort)))
- {
- /* Card identification */
+ FdoExt->Cards = IsaHwTryReadDataPort(FdoExt->ReadDataPort);
+
+ /* Card identification */
+ if (FdoExt->Cards > 0)
(VOID)IsaHwFillDeviceList(FdoExt);
- }
}
ReadPortExt->Flags &= ~ISAPNP_SCANNED_BY_READ_PORT;
diff --git a/drivers/bus/isapnp/isapnp.h b/drivers/bus/isapnp/isapnp.h
index ed4a6027a9b..d80d05dced1 100644
--- a/drivers/bus/isapnp/isapnp.h
+++ b/drivers/bus/isapnp/isapnp.h
@@ -23,6 +23,12 @@ extern "C" {
#define TAG_ISAPNP 'pasI'
+/** @brief Maximum size of resource data structure supported by the driver. */
+#define ISAPNP_MAX_RESOURCEDATA 0x1000
+
+/** @brief Maximum number of Start DF tags supported by the driver. */
+#define ISAPNP_MAX_ALTERNATIVES 8
+
typedef enum
{
dsStopped,
@@ -33,6 +39,7 @@ typedef struct _ISAPNP_IO
{
USHORT CurrentBase;
ISAPNP_IO_DESCRIPTION Description;
+ UCHAR Index;
} ISAPNP_IO, *PISAPNP_IO;
typedef struct _ISAPNP_IRQ
@@ -40,29 +47,92 @@ typedef struct _ISAPNP_IRQ
UCHAR CurrentNo;
UCHAR CurrentType;
ISAPNP_IRQ_DESCRIPTION Description;
+ UCHAR Index;
} ISAPNP_IRQ, *PISAPNP_IRQ;
typedef struct _ISAPNP_DMA
{
UCHAR CurrentChannel;
ISAPNP_DMA_DESCRIPTION Description;
+ UCHAR Index;
} ISAPNP_DMA, *PISAPNP_DMA;
+typedef struct _ISAPNP_MEMRANGE
+{
+ ULONG CurrentBase;
+ ULONG CurrentLength;
+ ISAPNP_MEMRANGE_DESCRIPTION Description;
+ UCHAR Index;
+} ISAPNP_MEMRANGE, *PISAPNP_MEMRANGE;
+
+typedef struct _ISAPNP_MEMRANGE32
+{
+ ULONG CurrentBase;
+ ULONG CurrentLength;
+ ISAPNP_MEMRANGE32_DESCRIPTION Description;
+ UCHAR Index;
+} ISAPNP_MEMRANGE32, *PISAPNP_MEMRANGE32;
+
+typedef struct _ISAPNP_COMPATIBLE_ID_ENTRY
+{
+ UCHAR VendorId[3];
+ USHORT ProdId;
+ LIST_ENTRY IdLink;
+} ISAPNP_COMPATIBLE_ID_ENTRY, *PISAPNP_COMPATIBLE_ID_ENTRY;
+
+typedef struct _ISAPNP_ALTERNATIVES
+{
+ ISAPNP_IO_DESCRIPTION Io[ISAPNP_MAX_ALTERNATIVES];
+ ISAPNP_IRQ_DESCRIPTION Irq[ISAPNP_MAX_ALTERNATIVES];
+ ISAPNP_DMA_DESCRIPTION Dma[ISAPNP_MAX_ALTERNATIVES];
+ ISAPNP_MEMRANGE_DESCRIPTION MemRange[ISAPNP_MAX_ALTERNATIVES];
+ ISAPNP_MEMRANGE32_DESCRIPTION MemRange32[ISAPNP_MAX_ALTERNATIVES];
+ UCHAR Priority[ISAPNP_MAX_ALTERNATIVES];
+ UCHAR IoIndex;
+ UCHAR IrqIndex;
+ UCHAR DmaIndex;
+ UCHAR MemRangeIndex;
+ UCHAR MemRange32Index;
+
+ _Field_range_(0, ISAPNP_MAX_ALTERNATIVES)
+ UCHAR Count;
+} ISAPNP_ALTERNATIVES, *PISAPNP_ALTERNATIVES;
+
typedef struct _ISAPNP_LOGICAL_DEVICE
{
PDEVICE_OBJECT Pdo;
- ISAPNP_LOGDEVID LogDevId;
+
+ /**
+ * @name The card data.
+ * @{
+ */
+ UCHAR CSN;
UCHAR VendorId[3];
USHORT ProdId;
ULONG SerialNumber;
+ /**@}*/
+
+ /**
+ * @name The logical device data.
+ * @{
+ */
+ UCHAR LDN;
+ UCHAR LogVendorId[3];
+ USHORT LogProdId;
+ LIST_ENTRY CompatibleIdList;
+ PSTR FriendlyName;
+ PISAPNP_ALTERNATIVES Alternatives;
+
ISAPNP_IO Io[8];
ISAPNP_IRQ Irq[2];
ISAPNP_DMA Dma[2];
- UCHAR CSN;
- UCHAR LDN;
+ ISAPNP_MEMRANGE MemRange[4];
+ ISAPNP_MEMRANGE32 MemRange32[4];
+ /**@}*/
ULONG Flags;
#define ISAPNP_PRESENT 0x00000001 /**< @brief Cleared when the device is
physically removed. */
+#define ISAPNP_HAS_MULTIPLE_LOGDEVS 0x00000002 /**< @brief Indicates if the parent
card has multiple logical devices. */
LIST_ENTRY DeviceLink;
} ISAPNP_LOGICAL_DEVICE, *PISAPNP_LOGICAL_DEVICE;
@@ -98,6 +168,7 @@ typedef struct _ISAPNP_FDO_EXTENSION
PDRIVER_OBJECT DriverObject;
PUCHAR ReadDataPort;
+ ULONG Cards;
LIST_ENTRY BusLink;
} ISAPNP_FDO_EXTENSION, *PISAPNP_FDO_EXTENSION;
@@ -165,6 +236,46 @@ IsaPnpReleaseDeviceDataLock(
KeSetEvent(&FdoExt->DeviceSyncEvent, IO_NO_INCREMENT, FALSE);
}
+FORCEINLINE
+BOOLEAN
+HasIoAlternatives(
+ _In_ PISAPNP_ALTERNATIVES Alternatives)
+{
+ return (Alternatives->Io[0].Length != 0);
+}
+
+FORCEINLINE
+BOOLEAN
+HasIrqAlternatives(
+ _In_ PISAPNP_ALTERNATIVES Alternatives)
+{
+ return (Alternatives->Irq[0].Mask != 0);
+}
+
+FORCEINLINE
+BOOLEAN
+HasDmaAlternatives(
+ _In_ PISAPNP_ALTERNATIVES Alternatives)
+{
+ return (Alternatives->Dma[0].Mask != 0);
+}
+
+FORCEINLINE
+BOOLEAN
+HasMemoryAlternatives(
+ _In_ PISAPNP_ALTERNATIVES Alternatives)
+{
+ return (Alternatives->MemRange[0].Length != 0);
+}
+
+FORCEINLINE
+BOOLEAN
+HasMemory32Alternatives(
+ _In_ PISAPNP_ALTERNATIVES Alternatives)
+{
+ return (Alternatives->MemRange32[0].Length != 0);
+}
+
/* isapnp.c */
CODE_SEG("PAGE")
@@ -218,10 +329,11 @@ IsaPnpRemoveLogicalDeviceDO(
/* hardware.c */
CODE_SEG("PAGE")
-NTSTATUS
+ULONG
IsaHwTryReadDataPort(
_In_ PUCHAR ReadDataPort);
+_Requires_lock_held_(FdoExt->DeviceSyncEvent)
CODE_SEG("PAGE")
NTSTATUS
IsaHwFillDeviceList(
diff --git a/drivers/bus/isapnp/isapnphw.h b/drivers/bus/isapnp/isapnphw.h
index cc33c320683..b3d8021a62c 100644
--- a/drivers/bus/isapnp/isapnphw.h
+++ b/drivers/bus/isapnp/isapnphw.h
@@ -4,6 +4,7 @@
* PURPOSE: Hardware definitions
* COPYRIGHT: Copyright 2010 Cameron Gutman <cameron.gutman(a)reactos.org>
* Copyright 2020 Hervé Poussineau <hpoussin(a)reactos.org>
+ * Copyright 2021 Dmitry Borisov <di.sean(a)protonmail.com>
*/
#pragma once
@@ -15,14 +16,6 @@ extern "C" {
#define ISAPNP_ADDRESS 0x279
#define ISAPNP_WRITE_DATA 0xA79
-#define ISAPNP_READ_PORT_MIN 0x203
-#define ISAPNP_READ_PORT_START 0x213
-#define ISAPNP_READ_PORT_MAX 0x3FF
-#define ISAPNP_READ_PORT_STEP 0x10
-
-#define ISAPNP_CSN_MIN 0x01
-#define ISAPNP_CSN_MAX 0x0F
-
#define ISAPNP_READPORT 0x00
#define ISAPNP_SERIALISOLATION 0x01
#define ISAPNP_CONFIGCONTROL 0x02
@@ -58,11 +51,6 @@ extern "C" {
#define ISAPNP_TAG_ENDDEP 0x07
#define ISAPNP_TAG_IOPORT 0x08
#define ISAPNP_TAG_FIXEDIO 0x09
-#define ISAPNP_TAG_RSVDSHORTA 0x0A
-#define ISAPNP_TAG_RSVDSHORTB 0x0B
-#define ISAPNP_TAG_RSVDSHORTC 0x0C
-#define ISAPNP_TAG_RSVDSHORTD 0x0D
-#define ISAPNP_TAG_VENDORSHORT 0x0E
#define ISAPNP_TAG_END 0x0F
#define ISAPNP_IS_LARGE_TAG(t) (((t) & 0x80))
@@ -70,26 +58,10 @@ extern "C" {
#define ISAPNP_TAG_MEMRANGE 0x81
#define ISAPNP_TAG_ANSISTR 0x82
#define ISAPNP_TAG_UNICODESTR 0x83
-#define ISAPNP_TAG_VENDORLONG 0x84
#define ISAPNP_TAG_MEM32RANGE 0x85
#define ISAPNP_TAG_FIXEDMEM32RANGE 0x86
-#define ISAPNP_TAG_RSVDLONG0 0xF0
-#define ISAPNP_TAG_RSVDLONG1 0xF1
-#define ISAPNP_TAG_RSVDLONG2 0xF2
-#define ISAPNP_TAG_RSVDLONG3 0xF3
-#define ISAPNP_TAG_RSVDLONG4 0xF4
-#define ISAPNP_TAG_RSVDLONG5 0xF5
-#define ISAPNP_TAG_RSVDLONG6 0xF6
-#define ISAPNP_TAG_RSVDLONG7 0xF7
-#define ISAPNP_TAG_RSVDLONG8 0xF8
-#define ISAPNP_TAG_RSVDLONG9 0xF9
-#define ISAPNP_TAG_RSVDLONGA 0xFA
-#define ISAPNP_TAG_RSVDLONGB 0xFB
-#define ISAPNP_TAG_RSVDLONGC 0xFC
-#define ISAPNP_TAG_RSVDLONGD 0xFD
-#define ISAPNP_TAG_RSVDLONGE 0xFE
-#define ISAPNP_TAG_RSVDLONGF 0xFF
-#define ISAPNP_TAG_PSEUDO_NEWBOARD 0x100
+
+#include <pshpack1.h>
typedef struct _ISAPNP_IDENTIFIER
{
@@ -106,14 +78,11 @@ typedef struct _ISAPNP_LOGDEVID
USHORT Flags;
} ISAPNP_LOGDEVID, *PISAPNP_LOGDEVID;
-typedef struct _ISAPNP_DEVICEID
+typedef struct _ISAPNP_COMPATID
{
- CHAR* Name;
USHORT VendorId;
USHORT ProdId;
-} ISAPNP_DEVICEID, *PISAPNP_DEVICEID;
-
-#include <pshpack1.h>
+} ISAPNP_COMPATID, *PISAPNP_COMPATID;
typedef struct _ISAPNP_IO_DESCRIPTION
{
@@ -124,6 +93,12 @@ typedef struct _ISAPNP_IO_DESCRIPTION
UCHAR Length;
} ISAPNP_IO_DESCRIPTION, *PISAPNP_IO_DESCRIPTION;
+typedef struct _ISAPNP_FIXED_IO_DESCRIPTION
+{
+ USHORT IoBase;
+ UCHAR Length;
+} ISAPNP_FIXED_IO_DESCRIPTION, *PISAPNP_FIXED_IO_DESCRIPTION;
+
typedef struct _ISAPNP_IRQ_DESCRIPTION
{
USHORT Mask;
@@ -136,6 +111,31 @@ typedef struct _ISAPNP_DMA_DESCRIPTION
UCHAR Information;
} ISAPNP_DMA_DESCRIPTION, *PISAPNP_DMA_DESCRIPTION;
+typedef struct _ISAPNP_MEMRANGE_DESCRIPTION
+{
+ UCHAR Information;
+ USHORT Minimum;
+ USHORT Maximum;
+ USHORT Alignment;
+ USHORT Length;
+} ISAPNP_MEMRANGE_DESCRIPTION, *PISAPNP_MEMRANGE_DESCRIPTION;
+
+typedef struct _ISAPNP_MEMRANGE32_DESCRIPTION
+{
+ UCHAR Information;
+ ULONG Minimum;
+ ULONG Maximum;
+ ULONG Alignment;
+ ULONG Length;
+} ISAPNP_MEMRANGE32_DESCRIPTION, *PISAPNP_MEMRANGE32_DESCRIPTION;
+
+typedef struct _ISAPNP_FIXEDMEMRANGE_DESCRIPTION
+{
+ UCHAR Information;
+ ULONG MemoryBase;
+ ULONG Length;
+} ISAPNP_FIXEDMEMRANGE_DESCRIPTION, *PISAPNP_FIXEDMEMRANGE_DESCRIPTION;
+
#include <poppack.h>
#ifdef __cplusplus
diff --git a/drivers/bus/isapnp/pdo.c b/drivers/bus/isapnp/pdo.c
index 6e3676a01cc..67a30891ac1 100644
--- a/drivers/bus/isapnp/pdo.c
+++ b/drivers/bus/isapnp/pdo.c
@@ -130,6 +130,11 @@ IsaPdoQueryId(
{
CharCount = sizeof("ISAPNP\\XXXFFFF");
+ if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS)
+ {
+ CharCount += sizeof("_DEV1234") - sizeof(ANSI_NULL);
+ }
+
Buffer = ExAllocatePoolWithTag(PagedPool,
CharCount * sizeof(WCHAR),
TAG_ISAPNP);
@@ -147,6 +152,19 @@ IsaPdoQueryId(
if (!NT_VERIFY(NT_SUCCESS(Status)))
goto Failure;
+ if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS)
+ {
+ Status = RtlStringCchPrintfExW(End,
+ Remaining,
+ NULL,
+ NULL,
+ 0,
+ L"_DEV%04X",
+ LogDev->LDN);
+ if (!NT_VERIFY(NT_SUCCESS(Status)))
+ goto Failure;
+ }
+
DPRINT("Device ID: '%S'\n", Buffer);
break;
}
@@ -157,6 +175,11 @@ IsaPdoQueryId(
sizeof("*PNPxxxx") +
sizeof(ANSI_NULL); /* multi-string */
+ if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS)
+ {
+ CharCount += sizeof("_DEV1234") - sizeof(ANSI_NULL);
+ }
+
Buffer = ExAllocatePoolWithTag(PagedPool,
CharCount * sizeof(WCHAR),
TAG_ISAPNP);
@@ -177,6 +200,19 @@ IsaPdoQueryId(
if (!NT_VERIFY(NT_SUCCESS(Status)))
goto Failure;
+ if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS)
+ {
+ Status = RtlStringCchPrintfExW(End,
+ Remaining,
+ &End,
+ &Remaining,
+ 0,
+ L"_DEV%04X",
+ LogDev->LDN);
+ if (!NT_VERIFY(NT_SUCCESS(Status)))
+ goto Failure;
+ }
+
DPRINT(" '%S'\n", Buffer);
++End;
@@ -190,8 +226,8 @@ IsaPdoQueryId(
&Remaining,
0,
L"*%.3S%04x",
- LogDev->VendorId,
- LogDev->ProdId);
+ LogDev->LogVendorId,
+ LogDev->LogProdId);
if (!NT_VERIFY(NT_SUCCESS(Status)))
goto Failure;
@@ -204,7 +240,57 @@ IsaPdoQueryId(
}
case BusQueryCompatibleIDs:
- return STATUS_NOT_IMPLEMENTED;
+ {
+ PLIST_ENTRY Entry;
+
+ for (Entry = LogDev->CompatibleIdList.Flink, CharCount = 0;
+ Entry != &LogDev->CompatibleIdList;
+ Entry = Entry->Flink)
+ {
+ CharCount += sizeof("*PNPxxxx");
+ }
+ CharCount += sizeof(ANSI_NULL); /* multi-string */
+
+ if (CharCount == sizeof(ANSI_NULL))
+ return Irp->IoStatus.Status;
+
+ Buffer = ExAllocatePoolWithTag(PagedPool,
+ CharCount * sizeof(WCHAR),
+ TAG_ISAPNP);
+ if (!Buffer)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ DPRINT("Compatible IDs:\n");
+
+ for (Entry = LogDev->CompatibleIdList.Flink, End = Buffer, Remaining =
CharCount;
+ Entry != &LogDev->CompatibleIdList;
+ Entry = Entry->Flink)
+ {
+ PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId =
+ CONTAINING_RECORD(Entry, ISAPNP_COMPATIBLE_ID_ENTRY, IdLink);
+
+ IdStart = End;
+ Status = RtlStringCchPrintfExW(End,
+ Remaining,
+ &End,
+ &Remaining,
+ 0,
+ L"*%.3S%04x",
+ CompatibleId->VendorId,
+ CompatibleId->ProdId);
+ if (!NT_VERIFY(NT_SUCCESS(Status)))
+ goto Failure;
+
+ DPRINT(" '%S'\n", IdStart);
+
+ ++End;
+ --Remaining;
+ }
+
+ *End = UNICODE_NULL;
+
+ break;
+ }
case BusQueryInstanceID:
{
@@ -319,6 +405,64 @@ IsaReadPortQueryId(
return STATUS_SUCCESS;
}
+static
+CODE_SEG("PAGE")
+NTSTATUS
+IsaPdoQueryDeviceText(
+ _In_ PISAPNP_PDO_EXTENSION PdoExt,
+ _Inout_ PIRP Irp,
+ _In_ PIO_STACK_LOCATION IrpSp)
+{
+ NTSTATUS Status;
+ PWCHAR Buffer;
+ size_t CharCount;
+
+ PAGED_CODE();
+
+ switch (IrpSp->Parameters.QueryDeviceText.DeviceTextType)
+ {
+ case DeviceTextDescription:
+ {
+ if (!PdoExt->IsaPnpDevice->FriendlyName)
+ return Irp->IoStatus.Status;
+
+ CharCount = strlen(PdoExt->IsaPnpDevice->FriendlyName) +
+ sizeof(ANSI_NULL);
+
+ if (CharCount == sizeof(ANSI_NULL))
+ return Irp->IoStatus.Status;
+
+ Buffer = ExAllocatePoolWithTag(PagedPool,
+ CharCount * sizeof(WCHAR),
+ TAG_ISAPNP);
+ if (!Buffer)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ Status = RtlStringCchPrintfExW(Buffer,
+ CharCount,
+ NULL,
+ NULL,
+ 0,
+ L"%hs",
+ PdoExt->IsaPnpDevice->FriendlyName);
+ if (!NT_VERIFY(NT_SUCCESS(Status)))
+ {
+ ExFreePoolWithTag(Buffer, TAG_ISAPNP);
+ return Status;
+ }
+
+ DPRINT("TextDescription: '%S'\n", Buffer);
+ break;
+ }
+
+ default:
+ return Irp->IoStatus.Status;
+ }
+
+ Irp->IoStatus.Information = (ULONG_PTR)Buffer;
+ return STATUS_SUCCESS;
+}
+
static
CODE_SEG("PAGE")
NTSTATUS
@@ -428,7 +572,7 @@ IsaPdoStartReadPort(
SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart;
/* We detected some ISAPNP cards */
- if (NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort)))
+ if (IsaHwTryReadDataPort(ReadDataPort) > 0)
{
SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart;
break;
@@ -473,7 +617,9 @@ IsaPdoStartReadPort(
PUCHAR ReadDataPort =
ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3);
/* Run the isolation protocol */
- if (NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort)))
+ FdoExt->Cards = IsaHwTryReadDataPort(ReadDataPort);
+
+ if (FdoExt->Cards > 0)
{
FdoExt->ReadDataPort = ReadDataPort;
@@ -482,16 +628,13 @@ IsaPdoStartReadPort(
/* Card identification */
Status = IsaHwFillDeviceList(FdoExt);
- if (FdoExt->DeviceCount > 0)
- {
- PdoExt->Flags |= ISAPNP_READ_PORT_ALLOW_FDO_SCAN |
- ISAPNP_SCANNED_BY_READ_PORT;
+ IsaPnpReleaseDeviceDataLock(FdoExt);
- IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations);
- IoInvalidateDeviceRelations(FdoExt->ReadPortPdo,
RemovalRelations);
- }
+ PdoExt->Flags |= ISAPNP_READ_PORT_ALLOW_FDO_SCAN |
+ ISAPNP_SCANNED_BY_READ_PORT;
- IsaPnpReleaseDeviceDataLock(FdoExt);
+ IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations);
+ IoInvalidateDeviceRelations(FdoExt->ReadPortPdo,
RemovalRelations);
return Status;
}
@@ -653,6 +796,7 @@ IsaPnpRemoveLogicalDeviceDO(
{
PISAPNP_PDO_EXTENSION PdoExt = Pdo->DeviceExtension;
PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
+ PLIST_ENTRY Entry;
PAGED_CODE();
ASSERT(LogDev);
@@ -665,6 +809,25 @@ IsaPnpRemoveLogicalDeviceDO(
if (PdoExt->ResourceList)
ExFreePoolWithTag(PdoExt->ResourceList, TAG_ISAPNP);
+ if (LogDev->FriendlyName)
+ ExFreePoolWithTag(LogDev->FriendlyName, TAG_ISAPNP);
+
+ if (LogDev->Alternatives)
+ ExFreePoolWithTag(LogDev->Alternatives, TAG_ISAPNP);
+
+ Entry = LogDev->CompatibleIdList.Flink;
+ while (Entry != &LogDev->CompatibleIdList)
+ {
+ PISAPNP_COMPATIBLE_ID_ENTRY CompatibleId =
+ CONTAINING_RECORD(Entry, ISAPNP_COMPATIBLE_ID_ENTRY, IdLink);
+
+ RemoveEntryList(&CompatibleId->IdLink);
+
+ Entry = Entry->Flink;
+
+ ExFreePoolWithTag(CompatibleId, TAG_ISAPNP);
+ }
+
ExFreePoolWithTag(LogDev, TAG_ISAPNP);
IoDeleteDevice(PdoExt->Common.Self);
@@ -790,6 +953,11 @@ IsaPdoPnp(
Status = IsaReadPortQueryId(Irp, IrpSp);
break;
+ case IRP_MN_QUERY_DEVICE_TEXT:
+ if (PdoExt->Common.Signature == IsaPnpLogicalDevice)
+ Status = IsaPdoQueryDeviceText(PdoExt, Irp, IrpSp);
+ break;
+
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
Status = IsaPdoFilterResourceRequirements(PdoExt, Irp, IrpSp);
break;