/* * 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 * Copyright 2020 Hervé Poussineau * Copyright 2021 Dmitry Borisov */ #include "isapnp.h" #define NDEBUG #include #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; }