diff --git a/drivers/bus/isapnp/hardware.c b/drivers/bus/isapnp/hardware.c index 188d1732447..26d6b120671 100644 --- a/drivers/bus/isapnp/hardware.c +++ b/drivers/bus/isapnp/hardware.c @@ -61,6 +61,30 @@ WriteByte( 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 @@ -1164,6 +1188,175 @@ ReadCurrentResources( 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( @@ -1405,6 +1598,110 @@ Deactivate: 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( diff --git a/drivers/bus/isapnp/isapnp.h b/drivers/bus/isapnp/isapnp.h index 19702f36274..ad48008251f 100644 --- a/drivers/bus/isapnp/isapnp.h +++ b/drivers/bus/isapnp/isapnp.h @@ -375,6 +375,13 @@ NTSTATUS IsaHwFillDeviceList( _In_ PISAPNP_FDO_EXTENSION FdoExt); +CODE_SEG("PAGE") +NTSTATUS +IsaHwConfigureDevice( + _In_ PISAPNP_FDO_EXTENSION FdoExt, + _In_ PISAPNP_LOGICAL_DEVICE LogicalDevice, + _In_ PCM_RESOURCE_LIST Resources); + _IRQL_requires_max_(DISPATCH_LEVEL) VOID IsaHwWakeDevice( diff --git a/drivers/bus/isapnp/isapnphw.h b/drivers/bus/isapnp/isapnphw.h index c41d6d1b7be..0023aac4fdf 100644 --- a/drivers/bus/isapnp/isapnphw.h +++ b/drivers/bus/isapnp/isapnphw.h @@ -31,10 +31,15 @@ extern "C" { #define ISAPNP_MEMBASE(n) (0x40 + ((n) * 8)) #define ISAPNP_MEMCONTROL(n) (0x42 + ((n) * 8)) #define MEMORY_UPPER_LIMIT 0x01 +#define MEMORY_USE_8_BIT_DECODER 0x00 +#define MEMORY_USE_16_BIT_DECODER 0x02 +#define MEMORY_USE_32_BIT_DECODER 0x06 #define ISAPNP_MEMLIMIT(n) (0x43 + ((n) * 8)) #define ISAPNP_IOBASE(n) (0x60 + ((n)*2)) #define ISAPNP_IRQNO(n) (0x70 + ((n)*2)) #define ISAPNP_IRQTYPE(n) (0x71 + ((n) * 2)) +#define IRQTYPE_LOW_LEVEL 0x01 +#define IRQTYPE_HIGH_EDGE 0x02 #define ISAPNP_DMACHANNEL(n) (0x74 + (n)) #define ISAPNP_MEMBASE32(n) ((n) == 0 ? 0x76 : (0x70 + (n) * 16)) #define ISAPNP_MEMCONTROL32(n) ((n) == 0 ? 0x7A : (0x74 + (n) * 16)) @@ -63,6 +68,8 @@ extern "C" { #define ISAPNP_IS_LARGE_TAG(t) (((t) & 0x80)) #define ISAPNP_LARGE_TAG_NAME(t) (t) #define ISAPNP_TAG_MEMRANGE 0x81 +#define MEMRANGE_16_BIT_MEMORY_MASK (0x10 | 0x08) +#define MEMRANGE_32_BIT_MEMORY_ONLY 0x18 #define ISAPNP_TAG_ANSISTR 0x82 #define ISAPNP_TAG_UNICODESTR 0x83 #define ISAPNP_TAG_MEM32RANGE 0x85 diff --git a/drivers/bus/isapnp/pdo.c b/drivers/bus/isapnp/pdo.c index 1ee0e51b7ea..f2014ffbc90 100644 --- a/drivers/bus/isapnp/pdo.c +++ b/drivers/bus/isapnp/pdo.c @@ -897,9 +897,19 @@ IsaPdoPnp( { IsaHwWakeDevice(PdoExt->IsaPnpDevice); - Status = STATUS_SUCCESS; + Status = IsaHwConfigureDevice(PdoExt->FdoExt, + PdoExt->IsaPnpDevice, + IrpSp->Parameters.StartDevice.AllocatedResources); + if (NT_SUCCESS(Status)) + { + IsaHwActivateDevice(PdoExt->FdoExt, PdoExt->IsaPnpDevice); + } + else + { + DPRINT1("Failed to configure CSN %u, LDN %u with status 0x%08lx\n", + PdoExt->IsaPnpDevice->CSN, PdoExt->IsaPnpDevice->LDN, Status); + } - IsaHwActivateDevice(PdoExt->FdoExt, PdoExt->IsaPnpDevice); IsaHwWaitForKey(); } else