mirror of
https://github.com/reactos/reactos.git
synced 2024-08-20 18:35:32 +00:00
1737 lines
46 KiB
C
1737 lines
46 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
|
|
VOID
|
|
WriteWord(
|
|
_In_ UCHAR Address,
|
|
_In_ USHORT Value)
|
|
{
|
|
WriteAddress(Address + 1);
|
|
WriteData((UCHAR)Value);
|
|
WriteAddress(Address);
|
|
WriteData(Value >> 8);
|
|
}
|
|
|
|
static
|
|
inline
|
|
VOID
|
|
WriteDoubleWord(
|
|
_In_ UCHAR Address,
|
|
_In_ ULONG Value)
|
|
{
|
|
WriteWord(Address + 2, (USHORT)Value);
|
|
WriteWord(Address, Value >> 16);
|
|
}
|
|
|
|
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
|
|
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_ PUCHAR ReadDataPort,
|
|
_In_ UCHAR LogDev)
|
|
{
|
|
WriteLogicalDeviceNumber(LogDev);
|
|
|
|
WriteByte(ISAPNP_IORANGECHECK,
|
|
ReadByte(ReadDataPort, ISAPNP_IORANGECHECK) & ~2);
|
|
|
|
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")
|
|
VOID
|
|
WriteResources(
|
|
_In_ PUCHAR ReadDataPort,
|
|
_In_ PISAPNP_LOGICAL_DEVICE LogDevice,
|
|
_In_ PCM_PARTIAL_RESOURCE_LIST PartialResourceList)
|
|
{
|
|
UCHAR i,
|
|
NumberOfIo = 0,
|
|
NumberOfIrq = 0,
|
|
NumberOfDma = 0,
|
|
NumberOfMemory = 0,
|
|
NumberOfMemory32 = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
WriteLogicalDeviceNumber(LogDevice->LDN);
|
|
|
|
for (i = 0; i < PartialResourceList->Count; i++)
|
|
{
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = &PartialResourceList->PartialDescriptors[i];
|
|
UCHAR Index;
|
|
|
|
switch (Descriptor->Type)
|
|
{
|
|
case CmResourceTypePort:
|
|
{
|
|
(VOID)FindIoDescriptor(LogDevice,
|
|
0,
|
|
Descriptor->u.Port.Start.LowPart,
|
|
Descriptor->u.Port.Start.LowPart +
|
|
Descriptor->u.Port.Length - 1,
|
|
NULL,
|
|
NULL,
|
|
&Index);
|
|
|
|
WriteWord(ISAPNP_IOBASE(Index), (USHORT)Descriptor->u.Port.Start.LowPart);
|
|
|
|
++NumberOfIo;
|
|
break;
|
|
}
|
|
|
|
case CmResourceTypeInterrupt:
|
|
{
|
|
(VOID)FindIrqDescriptor(LogDevice, Descriptor->u.Interrupt.Level, &Index);
|
|
|
|
WriteByte(ISAPNP_IRQNO(Index), (UCHAR)Descriptor->u.Interrupt.Level);
|
|
WriteByte(ISAPNP_IRQTYPE(Index),
|
|
Descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED
|
|
? IRQTYPE_HIGH_EDGE : IRQTYPE_LOW_LEVEL);
|
|
|
|
++NumberOfIrq;
|
|
break;
|
|
}
|
|
|
|
case CmResourceTypeDma:
|
|
{
|
|
(VOID)FindDmaDescriptor(LogDevice, Descriptor->u.Dma.Channel, &Index);
|
|
|
|
WriteByte(ISAPNP_DMACHANNEL(Index), (UCHAR)Descriptor->u.Dma.Channel);
|
|
|
|
++NumberOfDma;
|
|
break;
|
|
}
|
|
|
|
case CmResourceTypeMemory:
|
|
{
|
|
BOOLEAN Memory32;
|
|
UCHAR Information;
|
|
UCHAR MemoryControl = MEMORY_USE_8_BIT_DECODER;
|
|
|
|
(VOID)FindMemoryDescriptor(LogDevice,
|
|
Descriptor->u.Memory.Start.LowPart,
|
|
Descriptor->u.Memory.Start.LowPart +
|
|
Descriptor->u.Memory.Length - 1,
|
|
&Memory32,
|
|
&Information,
|
|
&Index);
|
|
|
|
if (!Memory32)
|
|
{
|
|
if (Information & MEMRANGE_16_BIT_MEMORY_MASK)
|
|
MemoryControl = MEMORY_USE_16_BIT_DECODER;
|
|
|
|
WriteWord(ISAPNP_MEMBASE(Index),
|
|
(USHORT)(Descriptor->u.Memory.Start.LowPart >> 8));
|
|
|
|
if (ReadMemoryControl(ReadDataPort, Index) & MEMORY_UPPER_LIMIT)
|
|
{
|
|
WriteByte(ISAPNP_MEMCONTROL(Index),
|
|
MemoryControl | MEMORY_UPPER_LIMIT);
|
|
WriteWord(ISAPNP_MEMLIMIT(Index),
|
|
(USHORT)((Descriptor->u.Memory.Start.LowPart +
|
|
Descriptor->u.Memory.Length) >> 8));
|
|
}
|
|
else
|
|
{
|
|
WriteByte(ISAPNP_MEMCONTROL(Index), MemoryControl);
|
|
WriteWord(ISAPNP_MEMLIMIT(Index),
|
|
(USHORT)(LENGTH_TO_RANGE_LENGTH(Descriptor->
|
|
u.Memory.Length) >> 8));
|
|
}
|
|
|
|
++NumberOfMemory;
|
|
}
|
|
else
|
|
{
|
|
WriteDoubleWord(ISAPNP_MEMBASE32(Index),
|
|
Descriptor->u.Memory.Start.LowPart);
|
|
|
|
if ((Information & MEMRANGE_16_BIT_MEMORY_MASK) == MEMRANGE_32_BIT_MEMORY_ONLY)
|
|
MemoryControl = MEMORY_USE_32_BIT_DECODER;
|
|
else if (Information & MEMRANGE_16_BIT_MEMORY_MASK)
|
|
MemoryControl = MEMORY_USE_16_BIT_DECODER;
|
|
|
|
if (ReadMemoryControl32(ReadDataPort, Index) & MEMORY_UPPER_LIMIT)
|
|
{
|
|
WriteByte(ISAPNP_MEMCONTROL32(Index),
|
|
MemoryControl | MEMORY_UPPER_LIMIT);
|
|
WriteDoubleWord(ISAPNP_MEMLIMIT32(Index),
|
|
Descriptor->u.Memory.Start.LowPart +
|
|
Descriptor->u.Memory.Length);
|
|
}
|
|
else
|
|
{
|
|
WriteByte(ISAPNP_MEMCONTROL32(Index), MemoryControl);
|
|
WriteDoubleWord(ISAPNP_MEMLIMIT32(Index),
|
|
LENGTH_TO_RANGE_LENGTH(Descriptor->u.Memory.Length));
|
|
}
|
|
|
|
++NumberOfMemory32;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = NumberOfIo; i < RTL_NUMBER_OF(LogDevice->Io); i++)
|
|
{
|
|
WriteWord(ISAPNP_IOBASE(i), 0);
|
|
}
|
|
for (i = NumberOfIrq; i < RTL_NUMBER_OF(LogDevice->Irq); i++)
|
|
{
|
|
WriteByte(ISAPNP_IRQNO(i), 0);
|
|
WriteByte(ISAPNP_IRQTYPE(i), 0);
|
|
}
|
|
for (i = NumberOfDma; i < RTL_NUMBER_OF(LogDevice->Dma); i++)
|
|
{
|
|
WriteByte(ISAPNP_DMACHANNEL(i), 4);
|
|
}
|
|
for (i = NumberOfMemory; i < RTL_NUMBER_OF(LogDevice->MemRange); i++)
|
|
{
|
|
WriteWord(ISAPNP_MEMBASE(i), 0);
|
|
WriteByte(ISAPNP_MEMCONTROL(i), 0);
|
|
WriteWord(ISAPNP_MEMLIMIT(i), 0);
|
|
}
|
|
for (i = NumberOfMemory32; i < RTL_NUMBER_OF(LogDevice->MemRange32); i++)
|
|
{
|
|
WriteDoubleWord(ISAPNP_MEMBASE32(i), 0);
|
|
WriteByte(ISAPNP_MEMCONTROL32(i), 0);
|
|
WriteDoubleWord(ISAPNP_MEMLIMIT32(i), 0);
|
|
}
|
|
}
|
|
|
|
CODE_SEG("PAGE")
|
|
UCHAR
|
|
IsaHwTryReadDataPort(
|
|
_In_ PUCHAR ReadDataPort)
|
|
{
|
|
ULONG NumberOfRead = 0;
|
|
UCHAR Csn = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
DPRINT("Setting read data port: 0x%p\n", ReadDataPort);
|
|
|
|
SendKey();
|
|
|
|
WriteByte(ISAPNP_CONFIGCONTROL,
|
|
ISAPNP_CONFIG_RESET_CSN | ISAPNP_CONFIG_WAIT_FOR_KEY);
|
|
KeStallExecutionProcessor(2000);
|
|
|
|
SendKey();
|
|
|
|
Wake(0x00);
|
|
KeStallExecutionProcessor(1000);
|
|
|
|
SetReadDataPort(ReadDataPort);
|
|
|
|
Wake(0x00);
|
|
|
|
while (TRUE)
|
|
{
|
|
ISAPNP_IDENTIFIER Identifier;
|
|
UCHAR i, j;
|
|
BOOLEAN Seen55aa = FALSE;
|
|
|
|
EnterIsolationState();
|
|
KeStallExecutionProcessor(1000);
|
|
|
|
RtlZeroMemory(&Identifier, sizeof(Identifier));
|
|
|
|
for (i = 0; i < sizeof(Identifier); i++)
|
|
{
|
|
UCHAR Byte = 0;
|
|
|
|
for (j = 0; j < RTL_BITS_OF(Byte); j++)
|
|
{
|
|
USHORT Data;
|
|
|
|
Data = ReadData(ReadDataPort) << 8;
|
|
KeStallExecutionProcessor(250);
|
|
Data |= ReadData(ReadDataPort);
|
|
KeStallExecutionProcessor(250);
|
|
|
|
Byte >>= 1;
|
|
|
|
if (Data == 0x55AA)
|
|
{
|
|
Byte |= 0x80;
|
|
Seen55aa = TRUE;
|
|
}
|
|
}
|
|
|
|
((PUCHAR)&Identifier)[i] = Byte;
|
|
}
|
|
|
|
++NumberOfRead;
|
|
|
|
if (Identifier.Checksum != 0x00 &&
|
|
Identifier.Checksum != IsaPnpChecksum(&Identifier))
|
|
{
|
|
DPRINT("Bad checksum\n");
|
|
break;
|
|
}
|
|
|
|
if (!Seen55aa)
|
|
{
|
|
DPRINT("Saw no sign of life\n");
|
|
break;
|
|
}
|
|
|
|
Csn++;
|
|
|
|
WriteCsn(Csn);
|
|
KeStallExecutionProcessor(1000);
|
|
|
|
Wake(0x00);
|
|
}
|
|
|
|
Wake(0x00);
|
|
|
|
if (NumberOfRead == 1)
|
|
{
|
|
DPRINT("Trying next read data port\n");
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
DPRINT("Found %u cards at read port 0x%p\n", Csn, ReadDataPort);
|
|
return Csn;
|
|
}
|
|
}
|
|
|
|
_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;
|
|
}
|
|
|
|
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(FdoExt->ReadDataPort, 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")
|
|
NTSTATUS
|
|
IsaHwConfigureDevice(
|
|
_In_ PISAPNP_FDO_EXTENSION FdoExt,
|
|
_In_ PISAPNP_LOGICAL_DEVICE LogicalDevice,
|
|
_In_ PCM_RESOURCE_LIST Resources)
|
|
{
|
|
UCHAR i,
|
|
NumberOfIo = 0,
|
|
NumberOfIrq = 0,
|
|
NumberOfDma = 0,
|
|
NumberOfMemory = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (!Resources)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
/* Validate the resource list */
|
|
for (i = 0; i < Resources->List[0].PartialResourceList.Count; i++)
|
|
{
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor =
|
|
&Resources->List[0].PartialResourceList.PartialDescriptors[i];
|
|
|
|
switch (Descriptor->Type)
|
|
{
|
|
case CmResourceTypePort:
|
|
{
|
|
if (++NumberOfIo > RTL_NUMBER_OF(LogicalDevice->Io))
|
|
return STATUS_INVALID_PARAMETER_1;
|
|
|
|
if (!FindIoDescriptor(LogicalDevice,
|
|
0,
|
|
Descriptor->u.Port.Start.LowPart,
|
|
Descriptor->u.Port.Start.LowPart +
|
|
Descriptor->u.Port.Length - 1,
|
|
NULL,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
return STATUS_RESOURCE_DATA_NOT_FOUND;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case CmResourceTypeInterrupt:
|
|
{
|
|
if (++NumberOfIrq > RTL_NUMBER_OF(LogicalDevice->Irq))
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
|
|
if (!FindIrqDescriptor(LogicalDevice, Descriptor->u.Interrupt.Level, NULL))
|
|
return STATUS_RESOURCE_DATA_NOT_FOUND;
|
|
|
|
break;
|
|
}
|
|
|
|
case CmResourceTypeDma:
|
|
{
|
|
if (++NumberOfDma > RTL_NUMBER_OF(LogicalDevice->Dma))
|
|
return STATUS_INVALID_PARAMETER_3;
|
|
|
|
if (!FindDmaDescriptor(LogicalDevice, Descriptor->u.Dma.Channel, NULL))
|
|
return STATUS_RESOURCE_DATA_NOT_FOUND;
|
|
|
|
break;
|
|
}
|
|
|
|
case CmResourceTypeMemory:
|
|
{
|
|
BOOLEAN Memory32;
|
|
|
|
if (++NumberOfMemory > RTL_NUMBER_OF(LogicalDevice->MemRange))
|
|
return STATUS_INVALID_PARAMETER_4;
|
|
|
|
if (!FindMemoryDescriptor(LogicalDevice,
|
|
Descriptor->u.Memory.Start.LowPart,
|
|
Descriptor->u.Memory.Start.LowPart +
|
|
Descriptor->u.Memory.Length - 1,
|
|
&Memory32,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
return STATUS_RESOURCE_DATA_NOT_FOUND;
|
|
}
|
|
|
|
if (!Memory32 && (Descriptor->u.Memory.Start.LowPart & 0xFF))
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
WriteResources(FdoExt->ReadDataPort, LogicalDevice, &Resources->List[0].PartialResourceList);
|
|
|
|
KeStallExecutionProcessor(10000);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
VOID
|
|
IsaHwWakeDevice(
|
|
_In_ PISAPNP_LOGICAL_DEVICE LogicalDevice)
|
|
{
|
|
SendKey();
|
|
Wake(LogicalDevice->CSN);
|
|
}
|
|
|
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
VOID
|
|
IsaHwActivateDevice(
|
|
_In_ PISAPNP_FDO_EXTENSION FdoExt,
|
|
_In_ PISAPNP_LOGICAL_DEVICE LogicalDevice)
|
|
{
|
|
ActivateDevice(FdoExt->ReadDataPort, LogicalDevice->LDN);
|
|
}
|
|
|
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
VOID
|
|
IsaHwDeactivateDevice(
|
|
_In_ PISAPNP_LOGICAL_DEVICE LogicalDevice)
|
|
{
|
|
DeactivateDevice(LogicalDevice->LDN);
|
|
}
|
|
|
|
_IRQL_requires_max_(DISPATCH_LEVEL)
|
|
VOID
|
|
IsaHwWaitForKey(VOID)
|
|
{
|
|
WaitForKey();
|
|
}
|