reactos/drivers/bus/isapnp/hardware.c
2021-06-20 19:24:31 +06:00

1470 lines
37 KiB
C

/*
* PROJECT: ReactOS ISA PnP Bus driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Hardware support code
* COPYRIGHT: Copyright 2010 Cameron Gutman <cameron.gutman@reactos.org>
* Copyright 2020 Hervé Poussineau <hpoussin@reactos.org>
* Copyright 2021 Dmitry Borisov <di.sean@protonmail.com>
*/
#include "isapnp.h"
#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
WriteAddress(
_In_ UCHAR Address)
{
WRITE_PORT_UCHAR((PUCHAR)ISAPNP_ADDRESS, Address);
}
static
inline
VOID
WriteData(
_In_ UCHAR Data)
{
WRITE_PORT_UCHAR((PUCHAR)ISAPNP_WRITE_DATA, Data);
}
static
inline
UCHAR
ReadData(
_In_ PUCHAR ReadDataPort)
{
return READ_PORT_UCHAR(ReadDataPort);
}
static
inline
VOID
WriteByte(
_In_ UCHAR Address,
_In_ UCHAR Value)
{
WriteAddress(Address);
WriteData(Value);
}
static
inline
UCHAR
ReadByte(
_In_ PUCHAR ReadDataPort,
_In_ UCHAR Address)
{
WriteAddress(Address);
return ReadData(ReadDataPort);
}
static
inline
USHORT
ReadWord(
_In_ PUCHAR ReadDataPort,
_In_ UCHAR Address)
{
return ((ReadByte(ReadDataPort, Address) << 8) |
(ReadByte(ReadDataPort, Address + 1)));
}
static
inline
ULONG
ReadDoubleWord(
_In_ PUCHAR ReadDataPort,
_In_ UCHAR Address)
{
return ((ReadWord(ReadDataPort, Address) << 8) |
(ReadWord(ReadDataPort, Address + 2)));
}
static
inline
VOID
SetReadDataPort(
_In_ PUCHAR ReadDataPort)
{
WriteByte(ISAPNP_READPORT, (UCHAR)((ULONG_PTR)ReadDataPort >> 2));
}
static
inline
VOID
EnterIsolationState(VOID)
{
WriteAddress(ISAPNP_SERIALISOLATION);
}
static
inline
VOID
WaitForKey(VOID)
{
WriteByte(ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_WAIT_FOR_KEY);
}
static
inline
VOID
ResetCsn(VOID)
{
WriteByte(ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_RESET_CSN);
}
static
inline
VOID
Wake(
_In_ UCHAR Csn)
{
WriteByte(ISAPNP_WAKE, Csn);
}
static
inline
UCHAR
ReadResourceData(
_In_ PUCHAR ReadDataPort)
{
return ReadByte(ReadDataPort, ISAPNP_RESOURCEDATA);
}
static
inline
UCHAR
ReadStatus(
_In_ PUCHAR ReadDataPort)
{
return ReadByte(ReadDataPort, ISAPNP_STATUS);
}
static
inline
VOID
WriteCsn(
_In_ UCHAR Csn)
{
WriteByte(ISAPNP_CARDSELECTNUMBER, Csn);
}
static
inline
VOID
WriteLogicalDeviceNumber(
_In_ UCHAR LogDev)
{
WriteByte(ISAPNP_LOGICALDEVICENUMBER, LogDev);
}
static
inline
VOID
ActivateDevice(
_In_ UCHAR LogDev)
{
WriteLogicalDeviceNumber(LogDev);
WriteByte(ISAPNP_ACTIVATE, 1);
}
static
inline
VOID
DeactivateDevice(
_In_ UCHAR LogDev)
{
WriteLogicalDeviceNumber(LogDev);
WriteByte(ISAPNP_ACTIVATE, 0);
}
static
inline
USHORT
ReadIoBase(
_In_ PUCHAR ReadDataPort,
_In_ UCHAR Index)
{
return ReadWord(ReadDataPort, ISAPNP_IOBASE(Index));
}
static
inline
UCHAR
ReadIrqNo(
_In_ PUCHAR ReadDataPort,
_In_ UCHAR Index)
{
return ReadByte(ReadDataPort, ISAPNP_IRQNO(Index)) & 0x0F;
}
static
inline
UCHAR
ReadIrqType(
_In_ PUCHAR ReadDataPort,
_In_ UCHAR Index)
{
return ReadByte(ReadDataPort, ISAPNP_IRQTYPE(Index));
}
static
inline
UCHAR
ReadDmaChannel(
_In_ PUCHAR ReadDataPort,
_In_ UCHAR Index)
{
return ReadByte(ReadDataPort, ISAPNP_DMACHANNEL(Index)) & 0x07;
}
static
inline
USHORT
ReadMemoryBase(
_In_ PUCHAR ReadDataPort,
_In_ UCHAR Index)
{
return ReadWord(ReadDataPort, ISAPNP_MEMBASE(Index));
}
static
inline
UCHAR
ReadMemoryControl(
_In_ PUCHAR ReadDataPort,
_In_ UCHAR Index)
{
return ReadByte(ReadDataPort, ISAPNP_MEMCONTROL(Index));
}
static
inline
USHORT
ReadMemoryLimit(
_In_ PUCHAR ReadDataPort,
_In_ UCHAR Index)
{
return ReadWord(ReadDataPort, ISAPNP_MEMLIMIT(Index));
}
static
inline
ULONG
ReadMemoryBase32(
_In_ PUCHAR ReadDataPort,
_In_ UCHAR Index)
{
return ReadDoubleWord(ReadDataPort, ISAPNP_MEMBASE32(Index));
}
static
inline
UCHAR
ReadMemoryControl32(
_In_ PUCHAR ReadDataPort,
_In_ UCHAR Index)
{
return ReadByte(ReadDataPort, ISAPNP_MEMCONTROL32(Index));
}
static
inline
ULONG
ReadMemoryLimit32(
_In_ PUCHAR ReadDataPort,
_In_ UCHAR Index)
{
return ReadDoubleWord(ReadDataPort, ISAPNP_MEMLIMIT32(Index));
}
static
inline
UCHAR
NextLFSR(
_In_ UCHAR Lfsr,
_In_ UCHAR InputBit)
{
UCHAR NextLfsr = Lfsr >> 1;
NextLfsr |= (((Lfsr ^ NextLfsr) ^ InputBit)) << 7;
return NextLfsr;
}
static
VOID
SendKey(VOID)
{
UCHAR i, Lfsr;
WriteAddress(0x00);
WriteAddress(0x00);
Lfsr = ISAPNP_LFSR_SEED;
for (i = 0; i < 32; i++)
{
WriteAddress(Lfsr);
Lfsr = NextLFSR(Lfsr, 0);
}
}
static
CODE_SEG("PAGE")
UCHAR
PeekByte(
_In_ PUCHAR ReadDataPort)
{
UCHAR i;
PAGED_CODE();
for (i = 0; i < 20; i++)
{
if (ReadStatus(ReadDataPort) & 0x01)
return ReadResourceData(ReadDataPort);
KeStallExecutionProcessor(1000);
}
return 0xFF;
}
static
CODE_SEG("PAGE")
VOID
Peek(
_In_ PUCHAR ReadDataPort,
_Out_writes_bytes_all_opt_(Length) PVOID Buffer,
_In_ USHORT Length)
{
USHORT i;
PAGED_CODE();
for (i = 0; i < Length; i++)
{
UCHAR Byte = PeekByte(ReadDataPort);
if (Buffer)
((PUCHAR)Buffer)[i] = Byte;
}
}
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
IsaPnpChecksum(
_In_ PISAPNP_IDENTIFIER Identifier)
{
UCHAR i, j, Lfsr;
PAGED_CODE();
Lfsr = ISAPNP_LFSR_SEED;
for (i = 0; i < FIELD_OFFSET(ISAPNP_IDENTIFIER, Checksum); i++)
{
UCHAR Byte = ((PUCHAR)Identifier)[i];
for (j = 0; j < RTL_BITS_OF(Byte); j++)
{
Lfsr = NextLFSR(Lfsr, Byte);
Byte >>= 1;
}
}
return Lfsr;
}
static
CODE_SEG("PAGE")
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,
_Out_writes_(ISAPNP_MAX_RESOURCEDATA) PUCHAR Buffer,
_In_ ULONG MaxLength,
_Out_ PUSHORT MaxLogDev)
{
PAGED_CODE();
*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);
Tag = ISAPNP_SMALL_TAG_NAME(Tag);
}
else
{
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 == 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)
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))
{
TagLen = ISAPNP_SMALL_TAG_LEN(Tag);
Tag = ISAPNP_SMALL_TAG_NAME(Tag);
}
else
{
TagLen = *ResourceData++;
TagLen += *ResourceData++ << 8;
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
CODE_SEG("PAGE")
BOOLEAN
ReadCurrentResources(
_In_ PUCHAR ReadDataPort,
_Inout_ PISAPNP_LOGICAL_DEVICE LogDevice)
{
UCHAR i;
PAGED_CODE();
DPRINT("%s for CSN %u, LDN %u\n", __FUNCTION__, LogDevice->CSN, LogDevice->LDN);
WriteLogicalDeviceNumber(LogDevice->LDN);
/* If the device is not activated by BIOS we just report a NULL resource list */
if (!(ReadByte(ReadDataPort, ISAPNP_ACTIVATE) & 1))
{
LogDevice->Flags &= ~ISAPNP_HAS_RESOURCES;
return FALSE;
}
for (i = 0; i < RTL_NUMBER_OF(LogDevice->Io); i++)
{
LogDevice->Io[i].CurrentBase = ReadIoBase(ReadDataPort, i);
/* Skip empty descriptors */
if (!LogDevice->Io[i].CurrentBase)
break;
}
for (i = 0; i < RTL_NUMBER_OF(LogDevice->Irq); i++)
{
LogDevice->Irq[i].CurrentNo = ReadIrqNo(ReadDataPort, i);
if (!LogDevice->Irq[i].CurrentNo)
break;
LogDevice->Irq[i].CurrentType = ReadIrqType(ReadDataPort, i);
}
for (i = 0; i < RTL_NUMBER_OF(LogDevice->Dma); i++)
{
LogDevice->Dma[i].CurrentChannel = ReadDmaChannel(ReadDataPort, i);
if (LogDevice->Dma[i].CurrentChannel == 4)
break;
}
for (i = 0; i < RTL_NUMBER_OF(LogDevice->MemRange); i++)
{
LogDevice->MemRange[i].CurrentBase = ReadMemoryBase(ReadDataPort, i) << 8;
if (!LogDevice->MemRange[i].CurrentBase)
break;
LogDevice->MemRange[i].CurrentLength = ReadMemoryLimit(ReadDataPort, i) << 8;
if (ReadMemoryControl(ReadDataPort, i) & MEMORY_UPPER_LIMIT)
{
LogDevice->MemRange[i].CurrentLength -= LogDevice->MemRange[i].CurrentBase;
}
else
{
LogDevice->MemRange[i].CurrentLength =
RANGE_LENGTH_TO_LENGTH(LogDevice->MemRange[i].CurrentLength);
}
}
for (i = 0; i < RTL_NUMBER_OF(LogDevice->MemRange32); i++)
{
LogDevice->MemRange32[i].CurrentBase = ReadMemoryBase32(ReadDataPort, i);
if (!LogDevice->MemRange32[i].CurrentBase)
break;
LogDevice->MemRange32[i].CurrentLength = ReadMemoryLimit32(ReadDataPort, i);
if (ReadMemoryControl32(ReadDataPort, i) & MEMORY_UPPER_LIMIT)
{
LogDevice->MemRange32[i].CurrentLength -= LogDevice->MemRange32[i].CurrentBase;
}
else
{
LogDevice->MemRange32[i].CurrentLength =
RANGE_LENGTH_TO_LENGTH(LogDevice->MemRange32[i].CurrentLength);
}
}
LogDevice->Flags |= ISAPNP_HAS_RESOURCES;
return TRUE;
}
static
CODE_SEG("PAGE")
INT
TryIsolate(
_In_ PUCHAR ReadDataPort)
{
ISAPNP_IDENTIFIER Identifier;
USHORT i, j;
BOOLEAN Seen55aa, SeenLife;
INT Csn = 0;
USHORT Byte, Data;
PAGED_CODE();
DPRINT("Setting read data port: 0x%p\n", ReadDataPort);
WaitForKey();
SendKey();
ResetCsn();
KeStallExecutionProcessor(2000);
WaitForKey();
SendKey();
Wake(0x00);
KeStallExecutionProcessor(1000);
SetReadDataPort(ReadDataPort);
while (TRUE)
{
EnterIsolationState();
KeStallExecutionProcessor(1000);
RtlZeroMemory(&Identifier, sizeof(Identifier));
Seen55aa = SeenLife = FALSE;
for (i = 0; i < 9; i++)
{
Byte = 0;
for (j = 0; j < 8; j++)
{
Data = ReadData(ReadDataPort);
KeStallExecutionProcessor(250);
Data = ((Data << 8) | ReadData(ReadDataPort));
KeStallExecutionProcessor(250);
Byte >>= 1;
if (Data != 0xFFFF)
{
SeenLife = TRUE;
if (Data == 0x55AA)
{
Byte |= 0x80;
Seen55aa = TRUE;
}
}
}
*(((PUCHAR)&Identifier) + i) = Byte;
}
if (!Seen55aa)
{
if (Csn)
{
DPRINT("Found no more cards\n");
}
else
{
if (SeenLife)
{
DPRINT("Saw life but no cards, trying new read port\n");
Csn = -1;
}
else
{
DPRINT("Saw no sign of life, abandoning isolation\n");
}
}
break;
}
if (Identifier.Checksum != IsaPnpChecksum(&Identifier))
{
DPRINT("Bad checksum, trying next read data port\n");
Csn = -1;
break;
}
Csn++;
WriteCsn(Csn);
KeStallExecutionProcessor(1000);
Wake(0x00);
}
WaitForKey();
if (Csn > 0)
{
DPRINT("Found %d cards at read port 0x%p\n", Csn, ReadDataPort);
}
return Csn;
}
static
VOID
DeviceActivation(
_In_ PISAPNP_LOGICAL_DEVICE IsaDevice,
_In_ BOOLEAN Activate)
{
WaitForKey();
SendKey();
Wake(IsaDevice->CSN);
if (Activate)
ActivateDevice(IsaDevice->LDN);
else
DeactivateDevice(IsaDevice->LDN);
WaitForKey();
}
_Requires_lock_held_(FdoExt->DeviceSyncEvent)
CODE_SEG("PAGE")
NTSTATUS
IsaHwFillDeviceList(
_In_ PISAPNP_FDO_EXTENSION FdoExt)
{
PISAPNP_LOGICAL_DEVICE LogDevice;
UCHAR Csn;
PLIST_ENTRY Entry;
PUCHAR ResourceData;
PAGED_CODE();
ASSERT(FdoExt->ReadDataPort);
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++)
{
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)
{
DPRINT1("Failed to allocate logical device!\n");
goto Deactivate;
}
InitializeListHead(&LogDevice->CompatibleIdList);
LogDevice->CSN = Csn;
LogDevice->LDN = LogDev;
Status = ParseTags(ResourceData, LogDev, LogDevice);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to parse tags with status 0x%08lx, CSN %u, LDN %u\n",
Status, LogDevice->CSN, LogDevice->LDN);
FreeLogicalDevice(LogDevice);
goto Deactivate;
}
if (!ReadCurrentResources(FdoExt->ReadDataPort, LogDevice))
DPRINT("Unable to read boot resources\n");
IsaPnpExtractAscii(LogDevice->VendorId, Identifier.VendorId);
LogDevice->ProdId = Identifier.ProdId;
LogDevice->SerialNumber = Identifier.Serial;
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")
ULONG
IsaHwTryReadDataPort(
_In_ PUCHAR ReadDataPort)
{
PAGED_CODE();
return TryIsolate(ReadDataPort);
}
_IRQL_requires_max_(DISPATCH_LEVEL)
NTSTATUS
IsaHwActivateDevice(
_In_ PISAPNP_LOGICAL_DEVICE LogicalDevice)
{
DeviceActivation(LogicalDevice,
TRUE);
return STATUS_SUCCESS;
}
_IRQL_requires_max_(DISPATCH_LEVEL)
NTSTATUS
IsaHwDeactivateDevice(
_In_ PISAPNP_LOGICAL_DEVICE LogicalDevice)
{
DeviceActivation(LogicalDevice,
FALSE);
return STATUS_SUCCESS;
}