[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.
This commit is contained in:
Dmitry Borisov 2021-03-20 20:50:34 +06:00
parent 7c897dfbd1
commit ca42de9c31
5 changed files with 1122 additions and 156 deletions

View file

@ -4,6 +4,7 @@
* PURPOSE: Hardware support code * PURPOSE: Hardware support code
* COPYRIGHT: Copyright 2010 Cameron Gutman <cameron.gutman@reactos.org> * COPYRIGHT: Copyright 2010 Cameron Gutman <cameron.gutman@reactos.org>
* Copyright 2020 Hervé Poussineau <hpoussin@reactos.org> * Copyright 2020 Hervé Poussineau <hpoussin@reactos.org>
* Copyright 2021 Dmitry Borisov <di.sean@protonmail.com>
*/ */
#include "isapnp.h" #include "isapnp.h"
@ -11,6 +12,17 @@
#define NDEBUG #define NDEBUG
#include <debug.h> #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 static
inline inline
VOID 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 static
CODE_SEG("PAGE") CODE_SEG("PAGE")
UCHAR UCHAR
@ -318,24 +348,48 @@ IsaPnpChecksum(
static static
CODE_SEG("PAGE") CODE_SEG("PAGE")
BOOLEAN VOID
ReadTags( IsaPnpExtractAscii(
_In_ PUCHAR ReadDataPort, _Out_writes_all_(3) PUCHAR Buffer,
_In_ USHORT LogDev, _In_ USHORT CompressedData)
_Inout_ PISAPNP_LOGICAL_DEVICE LogDevice)
{ {
BOOLEAN res = FALSE;
PVOID Buffer;
USHORT Tag, TagLen, MaxLen;
ULONG NumberOfIo = 0, NumberOfIrq = 0, NumberOfDma = 0;
PAGED_CODE(); PAGED_CODE();
LogDev += 1; 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,
_Out_writes_(ISAPNP_MAX_RESOURCEDATA) PUCHAR Buffer,
_In_ ULONG MaxLength,
_Out_ PUSHORT MaxLogDev)
{
PAGED_CODE();
*MaxLogDev = 0;
while (TRUE) while (TRUE)
{ {
UCHAR Tag;
USHORT TagLen;
if (MaxLength < 1)
return STATUS_BUFFER_OVERFLOW;
Tag = PeekByte(ReadDataPort); Tag = PeekByte(ReadDataPort);
if (Tag == 0)
{
DPRINT("Invalid tag\n");
return STATUS_INVALID_PARAMETER_1;
}
*Buffer++ = Tag;
--MaxLength;
if (ISAPNP_IS_SMALL_TAG(Tag)) if (ISAPNP_IS_SMALL_TAG(Tag))
{ {
TagLen = ISAPNP_SMALL_TAG_LEN(Tag); TagLen = ISAPNP_SMALL_TAG_LEN(Tag);
@ -343,64 +397,623 @@ ReadTags(
} }
else 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); Tag = ISAPNP_LARGE_TAG_NAME(Tag);
} }
if (Tag == 0xFF && TagLen == 0xFFFF)
{
DPRINT("Invalid tag\n");
return STATUS_INVALID_PARAMETER_2;
}
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) if (Tag == ISAPNP_TAG_END)
break; break;
}
Buffer = NULL; return STATUS_SUCCESS;
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))
{
MaxLen = sizeof(LogDevice->Io[NumberOfIo].Description);
Buffer = &LogDevice->Io[NumberOfIo].Description;
NumberOfIo++;
}
else if (Tag == ISAPNP_TAG_DMA && NumberOfDma < ARRAYSIZE(LogDevice->Dma))
{
MaxLen = sizeof(LogDevice->Dma[NumberOfDma].Description);
Buffer = &LogDevice->Dma[NumberOfDma].Description;
NumberOfDma++;
}
else if (LogDev == 0)
{
DPRINT1("Found unknown tag 0x%x (len %d)\n", Tag, TagLen);
}
if (Buffer && LogDev == 0) 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))
{ {
res = TRUE; TagLen = ISAPNP_SMALL_TAG_LEN(Tag);
if (MaxLen > TagLen) Tag = ISAPNP_SMALL_TAG_NAME(Tag);
{
Peek(ReadDataPort, Buffer, TagLen);
}
else
{
Peek(ReadDataPort, Buffer, MaxLen);
Peek(ReadDataPort, NULL, TagLen - MaxLen);
}
} }
else else
{ {
/* We don't want to read informations on this TagLen = *ResourceData++;
* logical device, or we don't know the tag. */ TagLen += *ResourceData++ << 8;
Peek(ReadDataPort, NULL, TagLen);
}
};
return res; Tag = ISAPNP_LARGE_TAG_NAME(Tag);
}
switch (Tag)
{
case ISAPNP_TAG_LOGDEVID:
{
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;
}
case ISAPNP_TAG_COMPATDEVID:
{
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;
}
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 static
@ -532,54 +1145,127 @@ DeviceActivation(
WaitForKey(); WaitForKey();
} }
static _Requires_lock_held_(FdoExt->DeviceSyncEvent)
CODE_SEG("PAGE") CODE_SEG("PAGE")
NTSTATUS NTSTATUS
ProbeIsaPnpBus( IsaHwFillDeviceList(
_In_ PISAPNP_FDO_EXTENSION FdoExt) _In_ PISAPNP_FDO_EXTENSION FdoExt)
{ {
PISAPNP_LOGICAL_DEVICE LogDevice; PISAPNP_LOGICAL_DEVICE LogDevice;
ISAPNP_IDENTIFIER Identifier; UCHAR Csn;
USHORT Csn;
USHORT LogDev;
ULONG i; ULONG i;
PLIST_ENTRY Entry;
PUCHAR ResourceData;
PAGED_CODE(); PAGED_CODE();
ASSERT(FdoExt->ReadDataPort); 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)
{ {
for (LogDev = 0; LogDev <= 0xFF; LogDev++) 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++)
{
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); LogDevice = ExAllocatePoolZero(NonPagedPool, sizeof(ISAPNP_LOGICAL_DEVICE), TAG_ISAPNP);
if (!LogDevice) if (!LogDevice)
return STATUS_NO_MEMORY; {
DPRINT1("Failed to allocate logical device!\n");
goto Deactivate;
}
InitializeListHead(&LogDevice->CompatibleIdList);
LogDevice->CSN = Csn; LogDevice->CSN = Csn;
LogDevice->LDN = LogDev; LogDevice->LDN = LogDev;
WaitForKey(); Status = ParseTags(ResourceData, LogDev, LogDevice);
SendKey(); if (!NT_SUCCESS(Status))
Wake(Csn);
Peek(FdoExt->ReadDataPort, &Identifier, sizeof(Identifier));
if (Identifier.VendorId & 0x80)
{ {
ExFreePoolWithTag(LogDevice, TAG_ISAPNP); DPRINT1("Failed to parse tags with status 0x%08lx, CSN %u, LDN %u\n",
return STATUS_SUCCESS; Status, LogDevice->CSN, LogDevice->LDN);
FreeLogicalDevice(LogDevice);
goto Deactivate;
} }
if (!ReadTags(FdoExt->ReadDataPort, LogDev, LogDevice))
break;
WriteLogicalDeviceNumber(LogDev); 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++) for (i = 0; i < ARRAYSIZE(LogDevice->Io); i++)
LogDevice->Io[i].CurrentBase = ReadIoBase(FdoExt->ReadDataPort, i); LogDevice->Io[i].CurrentBase = ReadIoBase(FdoExt->ReadDataPort, i);
for (i = 0; i < ARRAYSIZE(LogDevice->Irq); i++) for (i = 0; i < ARRAYSIZE(LogDevice->Irq); i++)
@ -592,27 +1278,37 @@ ProbeIsaPnpBus(
LogDevice->Dma[i].CurrentChannel = ReadDmaChannel(FdoExt->ReadDataPort, i); 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", IsaPnpExtractAscii(LogDevice->VendorId, Identifier.VendorId);
LogDevice->VendorId, LogDevice->ProdId, LogDevice->SerialNumber, LogDevice->Io[0].CurrentBase, LogDevice->Irq[0].CurrentNo); 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); InsertTailList(&FdoExt->DeviceListHead, &LogDevice->DeviceLink);
FdoExt->DeviceCount++; FdoExt->DeviceCount++;
/* Now we wait for the start device IRP */
Deactivate:
DeactivateDevice(LogDev);
} }
} }
ExFreePoolWithTag(ResourceData, TAG_ISAPNP);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
CODE_SEG("PAGE") CODE_SEG("PAGE")
NTSTATUS ULONG
IsaHwTryReadDataPort( IsaHwTryReadDataPort(
_In_ PUCHAR ReadDataPort) _In_ PUCHAR ReadDataPort)
{ {
PAGED_CODE(); PAGED_CODE();
return TryIsolate(ReadDataPort) > 0 ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES; return TryIsolate(ReadDataPort);
} }
_IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL)
@ -636,13 +1332,3 @@ IsaHwDeactivateDevice(
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
CODE_SEG("PAGE")
NTSTATUS
IsaHwFillDeviceList(
_In_ PISAPNP_FDO_EXTENSION FdoExt)
{
PAGED_CODE();
return ProbeIsaPnpBus(FdoExt);
}

View file

@ -676,11 +676,11 @@ IsaPnpFillDeviceRelations(
DPRINT("Rescan ISA PnP bus\n"); DPRINT("Rescan ISA PnP bus\n");
/* Run the isolation protocol */ /* Run the isolation protocol */
if (NT_SUCCESS(IsaHwTryReadDataPort(FdoExt->ReadDataPort))) FdoExt->Cards = IsaHwTryReadDataPort(FdoExt->ReadDataPort);
{
/* Card identification */ /* Card identification */
if (FdoExt->Cards > 0)
(VOID)IsaHwFillDeviceList(FdoExt); (VOID)IsaHwFillDeviceList(FdoExt);
}
} }
ReadPortExt->Flags &= ~ISAPNP_SCANNED_BY_READ_PORT; ReadPortExt->Flags &= ~ISAPNP_SCANNED_BY_READ_PORT;

View file

@ -23,6 +23,12 @@ extern "C" {
#define TAG_ISAPNP 'pasI' #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 typedef enum
{ {
dsStopped, dsStopped,
@ -33,6 +39,7 @@ typedef struct _ISAPNP_IO
{ {
USHORT CurrentBase; USHORT CurrentBase;
ISAPNP_IO_DESCRIPTION Description; ISAPNP_IO_DESCRIPTION Description;
UCHAR Index;
} ISAPNP_IO, *PISAPNP_IO; } ISAPNP_IO, *PISAPNP_IO;
typedef struct _ISAPNP_IRQ typedef struct _ISAPNP_IRQ
@ -40,29 +47,92 @@ typedef struct _ISAPNP_IRQ
UCHAR CurrentNo; UCHAR CurrentNo;
UCHAR CurrentType; UCHAR CurrentType;
ISAPNP_IRQ_DESCRIPTION Description; ISAPNP_IRQ_DESCRIPTION Description;
UCHAR Index;
} ISAPNP_IRQ, *PISAPNP_IRQ; } ISAPNP_IRQ, *PISAPNP_IRQ;
typedef struct _ISAPNP_DMA typedef struct _ISAPNP_DMA
{ {
UCHAR CurrentChannel; UCHAR CurrentChannel;
ISAPNP_DMA_DESCRIPTION Description; ISAPNP_DMA_DESCRIPTION Description;
UCHAR Index;
} ISAPNP_DMA, *PISAPNP_DMA; } 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 typedef struct _ISAPNP_LOGICAL_DEVICE
{ {
PDEVICE_OBJECT Pdo; PDEVICE_OBJECT Pdo;
ISAPNP_LOGDEVID LogDevId;
/**
* @name The card data.
* @{
*/
UCHAR CSN;
UCHAR VendorId[3]; UCHAR VendorId[3];
USHORT ProdId; USHORT ProdId;
ULONG SerialNumber; 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_IO Io[8];
ISAPNP_IRQ Irq[2]; ISAPNP_IRQ Irq[2];
ISAPNP_DMA Dma[2]; ISAPNP_DMA Dma[2];
UCHAR CSN; ISAPNP_MEMRANGE MemRange[4];
UCHAR LDN; ISAPNP_MEMRANGE32 MemRange32[4];
/**@}*/
ULONG Flags; ULONG Flags;
#define ISAPNP_PRESENT 0x00000001 /**< @brief Cleared when the device is physically removed. */ #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; LIST_ENTRY DeviceLink;
} ISAPNP_LOGICAL_DEVICE, *PISAPNP_LOGICAL_DEVICE; } ISAPNP_LOGICAL_DEVICE, *PISAPNP_LOGICAL_DEVICE;
@ -98,6 +168,7 @@ typedef struct _ISAPNP_FDO_EXTENSION
PDRIVER_OBJECT DriverObject; PDRIVER_OBJECT DriverObject;
PUCHAR ReadDataPort; PUCHAR ReadDataPort;
ULONG Cards;
LIST_ENTRY BusLink; LIST_ENTRY BusLink;
} ISAPNP_FDO_EXTENSION, *PISAPNP_FDO_EXTENSION; } ISAPNP_FDO_EXTENSION, *PISAPNP_FDO_EXTENSION;
@ -165,6 +236,46 @@ IsaPnpReleaseDeviceDataLock(
KeSetEvent(&FdoExt->DeviceSyncEvent, IO_NO_INCREMENT, FALSE); 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 */ /* isapnp.c */
CODE_SEG("PAGE") CODE_SEG("PAGE")
@ -218,10 +329,11 @@ IsaPnpRemoveLogicalDeviceDO(
/* hardware.c */ /* hardware.c */
CODE_SEG("PAGE") CODE_SEG("PAGE")
NTSTATUS ULONG
IsaHwTryReadDataPort( IsaHwTryReadDataPort(
_In_ PUCHAR ReadDataPort); _In_ PUCHAR ReadDataPort);
_Requires_lock_held_(FdoExt->DeviceSyncEvent)
CODE_SEG("PAGE") CODE_SEG("PAGE")
NTSTATUS NTSTATUS
IsaHwFillDeviceList( IsaHwFillDeviceList(

View file

@ -4,6 +4,7 @@
* PURPOSE: Hardware definitions * PURPOSE: Hardware definitions
* COPYRIGHT: Copyright 2010 Cameron Gutman <cameron.gutman@reactos.org> * COPYRIGHT: Copyright 2010 Cameron Gutman <cameron.gutman@reactos.org>
* Copyright 2020 Hervé Poussineau <hpoussin@reactos.org> * Copyright 2020 Hervé Poussineau <hpoussin@reactos.org>
* Copyright 2021 Dmitry Borisov <di.sean@protonmail.com>
*/ */
#pragma once #pragma once
@ -15,14 +16,6 @@ extern "C" {
#define ISAPNP_ADDRESS 0x279 #define ISAPNP_ADDRESS 0x279
#define ISAPNP_WRITE_DATA 0xA79 #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_READPORT 0x00
#define ISAPNP_SERIALISOLATION 0x01 #define ISAPNP_SERIALISOLATION 0x01
#define ISAPNP_CONFIGCONTROL 0x02 #define ISAPNP_CONFIGCONTROL 0x02
@ -58,11 +51,6 @@ extern "C" {
#define ISAPNP_TAG_ENDDEP 0x07 #define ISAPNP_TAG_ENDDEP 0x07
#define ISAPNP_TAG_IOPORT 0x08 #define ISAPNP_TAG_IOPORT 0x08
#define ISAPNP_TAG_FIXEDIO 0x09 #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_TAG_END 0x0F
#define ISAPNP_IS_LARGE_TAG(t) (((t) & 0x80)) #define ISAPNP_IS_LARGE_TAG(t) (((t) & 0x80))
@ -70,26 +58,10 @@ extern "C" {
#define ISAPNP_TAG_MEMRANGE 0x81 #define ISAPNP_TAG_MEMRANGE 0x81
#define ISAPNP_TAG_ANSISTR 0x82 #define ISAPNP_TAG_ANSISTR 0x82
#define ISAPNP_TAG_UNICODESTR 0x83 #define ISAPNP_TAG_UNICODESTR 0x83
#define ISAPNP_TAG_VENDORLONG 0x84
#define ISAPNP_TAG_MEM32RANGE 0x85 #define ISAPNP_TAG_MEM32RANGE 0x85
#define ISAPNP_TAG_FIXEDMEM32RANGE 0x86 #define ISAPNP_TAG_FIXEDMEM32RANGE 0x86
#define ISAPNP_TAG_RSVDLONG0 0xF0
#define ISAPNP_TAG_RSVDLONG1 0xF1 #include <pshpack1.h>
#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
typedef struct _ISAPNP_IDENTIFIER typedef struct _ISAPNP_IDENTIFIER
{ {
@ -106,14 +78,11 @@ typedef struct _ISAPNP_LOGDEVID
USHORT Flags; USHORT Flags;
} ISAPNP_LOGDEVID, *PISAPNP_LOGDEVID; } ISAPNP_LOGDEVID, *PISAPNP_LOGDEVID;
typedef struct _ISAPNP_DEVICEID typedef struct _ISAPNP_COMPATID
{ {
CHAR* Name;
USHORT VendorId; USHORT VendorId;
USHORT ProdId; USHORT ProdId;
} ISAPNP_DEVICEID, *PISAPNP_DEVICEID; } ISAPNP_COMPATID, *PISAPNP_COMPATID;
#include <pshpack1.h>
typedef struct _ISAPNP_IO_DESCRIPTION typedef struct _ISAPNP_IO_DESCRIPTION
{ {
@ -124,6 +93,12 @@ typedef struct _ISAPNP_IO_DESCRIPTION
UCHAR Length; UCHAR Length;
} ISAPNP_IO_DESCRIPTION, *PISAPNP_IO_DESCRIPTION; } 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 typedef struct _ISAPNP_IRQ_DESCRIPTION
{ {
USHORT Mask; USHORT Mask;
@ -136,6 +111,31 @@ typedef struct _ISAPNP_DMA_DESCRIPTION
UCHAR Information; UCHAR Information;
} ISAPNP_DMA_DESCRIPTION, *PISAPNP_DMA_DESCRIPTION; } 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> #include <poppack.h>
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -130,6 +130,11 @@ IsaPdoQueryId(
{ {
CharCount = sizeof("ISAPNP\\XXXFFFF"); CharCount = sizeof("ISAPNP\\XXXFFFF");
if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS)
{
CharCount += sizeof("_DEV1234") - sizeof(ANSI_NULL);
}
Buffer = ExAllocatePoolWithTag(PagedPool, Buffer = ExAllocatePoolWithTag(PagedPool,
CharCount * sizeof(WCHAR), CharCount * sizeof(WCHAR),
TAG_ISAPNP); TAG_ISAPNP);
@ -147,6 +152,19 @@ IsaPdoQueryId(
if (!NT_VERIFY(NT_SUCCESS(Status))) if (!NT_VERIFY(NT_SUCCESS(Status)))
goto Failure; 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); DPRINT("Device ID: '%S'\n", Buffer);
break; break;
} }
@ -157,6 +175,11 @@ IsaPdoQueryId(
sizeof("*PNPxxxx") + sizeof("*PNPxxxx") +
sizeof(ANSI_NULL); /* multi-string */ sizeof(ANSI_NULL); /* multi-string */
if (LogDev->Flags & ISAPNP_HAS_MULTIPLE_LOGDEVS)
{
CharCount += sizeof("_DEV1234") - sizeof(ANSI_NULL);
}
Buffer = ExAllocatePoolWithTag(PagedPool, Buffer = ExAllocatePoolWithTag(PagedPool,
CharCount * sizeof(WCHAR), CharCount * sizeof(WCHAR),
TAG_ISAPNP); TAG_ISAPNP);
@ -177,6 +200,19 @@ IsaPdoQueryId(
if (!NT_VERIFY(NT_SUCCESS(Status))) if (!NT_VERIFY(NT_SUCCESS(Status)))
goto Failure; 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); DPRINT(" '%S'\n", Buffer);
++End; ++End;
@ -190,8 +226,8 @@ IsaPdoQueryId(
&Remaining, &Remaining,
0, 0,
L"*%.3S%04x", L"*%.3S%04x",
LogDev->VendorId, LogDev->LogVendorId,
LogDev->ProdId); LogDev->LogProdId);
if (!NT_VERIFY(NT_SUCCESS(Status))) if (!NT_VERIFY(NT_SUCCESS(Status)))
goto Failure; goto Failure;
@ -204,7 +240,57 @@ IsaPdoQueryId(
} }
case BusQueryCompatibleIDs: 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: case BusQueryInstanceID:
{ {
@ -319,6 +405,64 @@ IsaReadPortQueryId(
return STATUS_SUCCESS; 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 static
CODE_SEG("PAGE") CODE_SEG("PAGE")
NTSTATUS NTSTATUS
@ -428,7 +572,7 @@ IsaPdoStartReadPort(
SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart; SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart;
/* We detected some ISAPNP cards */ /* We detected some ISAPNP cards */
if (NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort))) if (IsaHwTryReadDataPort(ReadDataPort) > 0)
{ {
SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart; SelectedPort = PartialDescriptor->u.Port.Start.u.LowPart;
break; break;
@ -473,7 +617,9 @@ IsaPdoStartReadPort(
PUCHAR ReadDataPort = ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3); PUCHAR ReadDataPort = ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3);
/* Run the isolation protocol */ /* Run the isolation protocol */
if (NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort))) FdoExt->Cards = IsaHwTryReadDataPort(ReadDataPort);
if (FdoExt->Cards > 0)
{ {
FdoExt->ReadDataPort = ReadDataPort; FdoExt->ReadDataPort = ReadDataPort;
@ -482,17 +628,14 @@ IsaPdoStartReadPort(
/* Card identification */ /* Card identification */
Status = IsaHwFillDeviceList(FdoExt); Status = IsaHwFillDeviceList(FdoExt);
if (FdoExt->DeviceCount > 0)
{
PdoExt->Flags |= ISAPNP_READ_PORT_ALLOW_FDO_SCAN |
ISAPNP_SCANNED_BY_READ_PORT;
IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations);
IoInvalidateDeviceRelations(FdoExt->ReadPortPdo, RemovalRelations);
}
IsaPnpReleaseDeviceDataLock(FdoExt); IsaPnpReleaseDeviceDataLock(FdoExt);
PdoExt->Flags |= ISAPNP_READ_PORT_ALLOW_FDO_SCAN |
ISAPNP_SCANNED_BY_READ_PORT;
IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations);
IoInvalidateDeviceRelations(FdoExt->ReadPortPdo, RemovalRelations);
return Status; return Status;
} }
else else
@ -653,6 +796,7 @@ IsaPnpRemoveLogicalDeviceDO(
{ {
PISAPNP_PDO_EXTENSION PdoExt = Pdo->DeviceExtension; PISAPNP_PDO_EXTENSION PdoExt = Pdo->DeviceExtension;
PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice; PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
PLIST_ENTRY Entry;
PAGED_CODE(); PAGED_CODE();
ASSERT(LogDev); ASSERT(LogDev);
@ -665,6 +809,25 @@ IsaPnpRemoveLogicalDeviceDO(
if (PdoExt->ResourceList) if (PdoExt->ResourceList)
ExFreePoolWithTag(PdoExt->ResourceList, TAG_ISAPNP); 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); ExFreePoolWithTag(LogDev, TAG_ISAPNP);
IoDeleteDevice(PdoExt->Common.Self); IoDeleteDevice(PdoExt->Common.Self);
@ -790,6 +953,11 @@ IsaPdoPnp(
Status = IsaReadPortQueryId(Irp, IrpSp); Status = IsaReadPortQueryId(Irp, IrpSp);
break; break;
case IRP_MN_QUERY_DEVICE_TEXT:
if (PdoExt->Common.Signature == IsaPnpLogicalDevice)
Status = IsaPdoQueryDeviceText(PdoExt, Irp, IrpSp);
break;
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
Status = IsaPdoFilterResourceRequirements(PdoExt, Irp, IrpSp); Status = IsaPdoFilterResourceRequirements(PdoExt, Irp, IrpSp);
break; break;