mirror of
https://github.com/reactos/reactos.git
synced 2024-11-09 16:20:37 +00:00
cd5c660bf9
We only can safely sync up to r46941. svn path=/branches/header-work/; revision=47096
1747 lines
40 KiB
C
1747 lines
40 KiB
C
/* $Id$
|
|
*
|
|
* PROJECT: ReactOS ISA PnP Bus driver
|
|
* FILE: isapnp.c
|
|
* PURPOSE: Driver entry
|
|
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
* NOTE: Parts adapted from linux ISA PnP driver
|
|
* UPDATE HISTORY:
|
|
* 01-05-2001 CSH Created
|
|
*/
|
|
#include <isapnp.h>
|
|
|
|
#ifndef NDEBUG
|
|
#define NDEBUG
|
|
#endif
|
|
#include <debug.h>
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
|
|
// Make the initialization routines discardable, so that they
|
|
// don't waste space
|
|
|
|
#pragma alloc_text(init, DriverEntry)
|
|
|
|
|
|
#endif /* ALLOC_PRAGMA */
|
|
|
|
|
|
PUCHAR IsaPnPReadPort;
|
|
|
|
|
|
#define UCHAR2USHORT(v0, v1) \
|
|
((v1 << 8) | v0)
|
|
|
|
#define UCHAR2ULONG(v0, v1, v2, v3) \
|
|
((UCHAR2USHORT(v2, v3) << 16) | UCHAR2USHORT(v0, v1))
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
struct
|
|
{
|
|
PCH Name;
|
|
} SmallTags[] = {
|
|
{"Unknown Small Tag"},
|
|
{"ISAPNP_SRIN_VERSION"},
|
|
{"ISAPNP_SRIN_LDEVICE_ID"},
|
|
{"ISAPNP_SRIN_CDEVICE_ID"},
|
|
{"ISAPNP_SRIN_IRQ_FORMAT"},
|
|
{"ISAPNP_SRIN_DMA_FORMAT"},
|
|
{"ISAPNP_SRIN_START_DFUNCTION"},
|
|
{"ISAPNP_SRIN_END_DFUNCTION"},
|
|
{"ISAPNP_SRIN_IO_DESCRIPTOR"},
|
|
{"ISAPNP_SRIN_FL_IO_DESCRIPOTOR"},
|
|
{"Reserved Small Tag"},
|
|
{"Reserved Small Tag"},
|
|
{"Reserved Small Tag"},
|
|
{"Reserved Small Tag"},
|
|
{"ISAPNP_SRIN_VENDOR_DEFINED"},
|
|
{"ISAPNP_SRIN_END_TAG"}
|
|
};
|
|
|
|
struct
|
|
{
|
|
PCH Name;
|
|
} LargeTags[] = {
|
|
{"Unknown Large Tag"},
|
|
{"ISAPNP_LRIN_MEMORY_RANGE"},
|
|
{"ISAPNP_LRIN_ID_STRING_ANSI"},
|
|
{"ISAPNP_LRIN_ID_STRING_UNICODE"},
|
|
{"ISAPNP_LRIN_VENDOR_DEFINED"},
|
|
{"ISAPNP_LRIN_MEMORY_RANGE32"},
|
|
{"ISAPNP_LRIN_FL_MEMORY_RANGE32"}
|
|
};
|
|
|
|
PCSZ TagName(ULONG Tag, BOOLEAN Small)
|
|
{
|
|
if (Small && (Tag <= ISAPNP_SRIN_END_TAG)) {
|
|
return SmallTags[Tag].Name;
|
|
} else if (Tag <= ISAPNP_LRIN_FL_MEMORY_RANGE32){
|
|
return LargeTags[Tag].Name;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#endif
|
|
|
|
static __inline VOID WriteData(UCHAR Value)
|
|
{
|
|
WRITE_PORT_UCHAR((PUCHAR)ISAPNP_WRITE_PORT, Value);
|
|
}
|
|
|
|
static __inline VOID WriteAddress(UCHAR Value)
|
|
{
|
|
WRITE_PORT_UCHAR((PUCHAR)ISAPNP_ADDRESS_PORT, Value);
|
|
KeStallExecutionProcessor(20);
|
|
}
|
|
|
|
static __inline UCHAR ReadData(VOID)
|
|
{
|
|
return READ_PORT_UCHAR(IsaPnPReadPort);
|
|
}
|
|
|
|
static UCHAR ReadUchar(UCHAR Index)
|
|
{
|
|
WriteAddress(Index);
|
|
return ReadData();
|
|
}
|
|
|
|
#if 0
|
|
static USHORT ReadUshort(UCHAR Index)
|
|
{
|
|
USHORT Value;
|
|
|
|
Value = ReadUchar(Index);
|
|
Value = (Value << 8) + ReadUchar(Index + 1);
|
|
return Value;
|
|
}
|
|
|
|
static ULONG ReadUlong(UCHAR Index)
|
|
{
|
|
ULONG Value;
|
|
|
|
Value = ReadUchar(Index);
|
|
Value = (Value << 8) + ReadUchar(Index + 1);
|
|
Value = (Value << 8) + ReadUchar(Index + 2);
|
|
Value = (Value << 8) + ReadUchar(Index + 3);
|
|
return Value;
|
|
}
|
|
#endif
|
|
|
|
static VOID WriteUchar(UCHAR Index, UCHAR Value)
|
|
{
|
|
WriteAddress(Index);
|
|
WriteData(Value);
|
|
}
|
|
|
|
#if 0
|
|
static VOID WriteUshort(UCHAR Index, USHORT Value)
|
|
{
|
|
WriteUchar(Index, Value >> 8);
|
|
WriteUchar(Index + 1, Value);
|
|
}
|
|
|
|
static VOID WriteUlong(UCHAR Index, ULONG Value)
|
|
{
|
|
WriteUchar(Index, Value >> 24);
|
|
WriteUchar(Index + 1, Value >> 16);
|
|
WriteUchar(Index + 2, Value >> 8);
|
|
WriteUchar(Index + 3, Value);
|
|
}
|
|
#endif
|
|
|
|
static __inline VOID SetReadDataPort(ULONG_PTR Port)
|
|
{
|
|
IsaPnPReadPort = (PUCHAR)Port;
|
|
WriteUchar(0x00, (UCHAR) (Port >> 2));
|
|
KeStallExecutionProcessor(100);
|
|
}
|
|
|
|
static VOID SendKey(VOID)
|
|
{
|
|
ULONG i;
|
|
UCHAR msb;
|
|
UCHAR code;
|
|
|
|
/* FIXME: Is there something better? */
|
|
KeStallExecutionProcessor(1000);
|
|
WriteAddress(0x00);
|
|
WriteAddress(0x00);
|
|
|
|
code = 0x6a;
|
|
WriteAddress(code);
|
|
for (i = 1; i < 32; i++) {
|
|
msb = ((code & 0x01) ^ ((code & 0x02) >> 1)) << 7;
|
|
code = (code >> 1) | msb;
|
|
WriteAddress(code);
|
|
}
|
|
}
|
|
|
|
/* Place all PnP cards in wait-for-key state */
|
|
static VOID SendWait(VOID)
|
|
{
|
|
WriteUchar(0x02, 0x02);
|
|
}
|
|
|
|
static VOID SendWake(UCHAR csn)
|
|
{
|
|
WriteUchar(ISAPNP_CARD_WAKECSN, csn);
|
|
}
|
|
|
|
#if 0
|
|
static VOID SelectLogicalDevice(UCHAR LogicalDevice)
|
|
{
|
|
WriteUchar(ISAPNP_CARD_LOG_DEVICE_NUM, LogicalDevice);
|
|
}
|
|
|
|
static VOID ActivateLogicalDevice(UCHAR LogicalDevice)
|
|
{
|
|
SelectLogicalDevice(LogicalDevice);
|
|
WriteUchar(ISAPNP_CONTROL_ACTIVATE, 0x1);
|
|
KeStallExecutionProcessor(250);
|
|
}
|
|
|
|
static VOID DeactivateLogicalDevice(UCHAR LogicalDevice)
|
|
{
|
|
SelectLogicalDevice(LogicalDevice);
|
|
WriteUchar(ISAPNP_CONTROL_ACTIVATE, 0x0);
|
|
KeStallExecutionProcessor(500);
|
|
}
|
|
#endif
|
|
|
|
#define READ_DATA_PORT_STEP 32 /* Minimum is 4 */
|
|
|
|
static ULONG_PTR FindNextReadPort(VOID)
|
|
{
|
|
ULONG_PTR Port;
|
|
|
|
|
|
|
|
Port = (ULONG_PTR)IsaPnPReadPort;
|
|
|
|
while (TRUE) {
|
|
|
|
Port += READ_DATA_PORT_STEP;
|
|
|
|
|
|
|
|
if (Port > ISAPNP_MAX_READ_PORT)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We cannot use NE2000 probe spaces for
|
|
|
|
* ISAPnP or we will lock up machines
|
|
|
|
*/
|
|
|
|
if ((Port < 0x280) || (Port > 0x380))
|
|
|
|
{
|
|
|
|
return Port;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static BOOLEAN IsolateReadDataPortSelect(VOID)
|
|
{
|
|
ULONG_PTR Port;
|
|
|
|
SendWait();
|
|
SendKey();
|
|
|
|
/* Control: reset CSN and conditionally everything else too */
|
|
WriteUchar(0x02, 0x05);
|
|
KeStallExecutionProcessor(2000);
|
|
|
|
SendWait();
|
|
SendKey();
|
|
SendWake(0x00);
|
|
|
|
Port = FindNextReadPort();
|
|
if (Port == 0) {
|
|
SendWait();
|
|
return FALSE;
|
|
}
|
|
|
|
SetReadDataPort(Port);
|
|
KeStallExecutionProcessor(1000);
|
|
WriteAddress(0x01);
|
|
KeStallExecutionProcessor(1000);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Isolate (assign uniqued CSN) to all ISA PnP devices
|
|
*/
|
|
static ULONG IsolatePnPCards(VOID)
|
|
{
|
|
UCHAR checksum = 0x6a;
|
|
UCHAR chksum = 0x00;
|
|
UCHAR bit = 0x00;
|
|
ULONG data;
|
|
ULONG csn = 0;
|
|
ULONG i;
|
|
ULONG iteration = 1;
|
|
|
|
DPRINT("Called\n");
|
|
|
|
IsaPnPReadPort = (PUCHAR)(ISAPNP_MIN_READ_PORT - READ_DATA_PORT_STEP);
|
|
if (!IsolateReadDataPortSelect()) {
|
|
DPRINT("Could not set read data port\n");
|
|
return 0;
|
|
}
|
|
|
|
while (TRUE) {
|
|
for (i = 1; i <= 64; i++) {
|
|
data = ReadData() << 8;
|
|
KeStallExecutionProcessor(250);
|
|
data = data | ReadData();
|
|
KeStallExecutionProcessor(250);
|
|
if (data == 0x55aa)
|
|
bit = 0x01;
|
|
checksum = ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7) | (checksum >> 1);
|
|
bit = 0x00;
|
|
}
|
|
for (i = 65; i <= 72; i++) {
|
|
data = ReadData() << 8;
|
|
KeStallExecutionProcessor(250);
|
|
data = data | ReadData();
|
|
KeStallExecutionProcessor(250);
|
|
if (data == 0x55aa)
|
|
chksum |= (1 << (i - 65));
|
|
}
|
|
if ((checksum != 0x00) && (checksum == chksum)) {
|
|
csn++;
|
|
|
|
WriteUchar(0x06, (UCHAR) csn);
|
|
KeStallExecutionProcessor(250);
|
|
iteration++;
|
|
SendWake(0x00);
|
|
SetReadDataPort((ULONG_PTR)IsaPnPReadPort);
|
|
KeStallExecutionProcessor(1000);
|
|
WriteAddress(0x01);
|
|
KeStallExecutionProcessor(1000);
|
|
goto next;
|
|
}
|
|
if (iteration == 1) {
|
|
if (!IsolateReadDataPortSelect()) {
|
|
DPRINT("Could not set read data port\n");
|
|
return 0;
|
|
}
|
|
} else if (iteration > 1) {
|
|
break;
|
|
}
|
|
next:
|
|
checksum = 0x6a;
|
|
chksum = 0x00;
|
|
bit = 0x00;
|
|
}
|
|
SendWait();
|
|
return csn;
|
|
}
|
|
|
|
|
|
static VOID Peek(PUCHAR Data, ULONG Count)
|
|
{
|
|
ULONG i, j;
|
|
UCHAR d = 0;
|
|
|
|
for (i = 1; i <= Count; i++) {
|
|
for (j = 0; j < 20; j++) {
|
|
d = ReadUchar(0x05);
|
|
if (d & 0x1)
|
|
break;
|
|
KeStallExecutionProcessor(100);
|
|
}
|
|
if (!(d & 0x1)) {
|
|
if (Data != NULL)
|
|
*Data++ = 0xff;
|
|
continue;
|
|
}
|
|
d = ReadUchar(0x04); /* PRESDI */
|
|
if (Data != NULL)
|
|
*Data++ = d;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Skip specified number of bytes from stream
|
|
*/
|
|
static VOID Skip(ULONG Count)
|
|
{
|
|
Peek(NULL, Count);
|
|
}
|
|
|
|
|
|
/*
|
|
* Read one tag from stream
|
|
*/
|
|
static BOOLEAN ReadTag(PUCHAR Type,
|
|
PUSHORT Size,
|
|
PBOOLEAN Small)
|
|
{
|
|
UCHAR tag, tmp[2];
|
|
|
|
Peek(&tag, 1);
|
|
if (tag == 0) {
|
|
/* Invalid tag */
|
|
DPRINT("Invalid tag with value 0\n");
|
|
#ifndef NDEBUG
|
|
for (;;);
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
if (tag & ISAPNP_RESOURCE_ITEM_TYPE) {
|
|
/* Large resource item */
|
|
*Type = (tag & 0x7f);
|
|
Peek(tmp, 2);
|
|
*Size = UCHAR2USHORT(tmp[0], tmp[1]);
|
|
*Small = FALSE;
|
|
#ifndef NDEBUG
|
|
if (*Type > ISAPNP_LRIN_FL_MEMORY_RANGE32) {
|
|
DPRINT("Invalid large tag with value 0x%X\n", *Type);
|
|
for (;;);
|
|
}
|
|
#endif
|
|
} else {
|
|
/* Small resource item */
|
|
*Type = (tag >> 3) & 0x0f;
|
|
*Size = tag & 0x07;
|
|
*Small = TRUE;
|
|
#ifndef NDEBUG
|
|
if (*Type > ISAPNP_SRIN_END_TAG) {
|
|
DPRINT("Invalid small tag with value 0x%X\n", *Type);
|
|
for (;;);
|
|
}
|
|
#endif
|
|
}
|
|
#if 0
|
|
DPRINT("Tag = 0x%X, Type = 0x%X, Size = %d (%s)\n",
|
|
tag, *Type, *Size, TagName(*Type, *Small));
|
|
#endif
|
|
/* Probably invalid data */
|
|
if ((*Type == 0xff) && (*Size == 0xffff)) {
|
|
DPRINT("Invalid data (Type 0x%X Size 0x%X)\n", *Type, *Size);
|
|
for (;;);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Parse ANSI name for ISA PnP logical device
|
|
*/
|
|
static NTSTATUS ParseAnsiName(PUNICODE_STRING Name, PUSHORT Size)
|
|
{
|
|
ANSI_STRING AnsiString;
|
|
UCHAR Buffer[256];
|
|
USHORT size1;
|
|
|
|
size1 = (*Size >= sizeof(Buffer)) ? (sizeof(Buffer) - 1) : *Size;
|
|
|
|
Peek(Buffer, size1);
|
|
Buffer[size1] = '\0';
|
|
*Size -= size1;
|
|
|
|
/* Clean whitespace from end of string */
|
|
while ((size1 > 0) && (Buffer[--size1] == ' '))
|
|
Buffer[size1] = '\0';
|
|
|
|
DPRINT("ANSI name: %s\n", Buffer);
|
|
|
|
RtlInitAnsiString(&AnsiString, (PCSZ)&Buffer);
|
|
return RtlAnsiStringToUnicodeString(Name, &AnsiString, TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
* Add a resource list to the
|
|
* resource lists of a logical device
|
|
*/
|
|
static NTSTATUS AddResourceList(
|
|
PISAPNP_LOGICAL_DEVICE LogicalDevice,
|
|
ULONG Priority,
|
|
PISAPNP_CONFIGURATION_LIST *NewList)
|
|
{
|
|
PISAPNP_CONFIGURATION_LIST List;
|
|
|
|
DPRINT("Adding resource list for logical device %d on card %d (Priority %d)\n",
|
|
LogicalDevice->Number,
|
|
LogicalDevice->Card->CardId,
|
|
Priority);
|
|
|
|
List = (PISAPNP_CONFIGURATION_LIST)
|
|
ExAllocatePoolWithTag(PagedPool, sizeof(ISAPNP_CONFIGURATION_LIST), TAG_ISAPNP);
|
|
if (!List)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
RtlZeroMemory(List, sizeof(ISAPNP_CONFIGURATION_LIST));
|
|
|
|
List->Priority = Priority;
|
|
|
|
InitializeListHead(&List->ListHead);
|
|
|
|
InsertTailList(&LogicalDevice->Configuration, &List->ListEntry);
|
|
|
|
*NewList = List;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* Add a resource entry to the
|
|
* resource list of a logical device
|
|
*/
|
|
static NTSTATUS AddResourceDescriptor(
|
|
PISAPNP_LOGICAL_DEVICE LogicalDevice,
|
|
ULONG Priority,
|
|
ULONG Option,
|
|
PISAPNP_DESCRIPTOR *Descriptor)
|
|
{
|
|
PLIST_ENTRY CurrentEntry;
|
|
PISAPNP_CONFIGURATION_LIST List;
|
|
PISAPNP_DESCRIPTOR d;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("Adding resource descriptor for logical device %d on card %d (%d of %d)\n",
|
|
LogicalDevice->Number,
|
|
LogicalDevice->Card->CardId,
|
|
LogicalDevice->CurrentDescriptorCount,
|
|
LogicalDevice->DescriptorCount);
|
|
|
|
d = (PISAPNP_DESCRIPTOR)
|
|
ExAllocatePoolWithTag(PagedPool, sizeof(ISAPNP_DESCRIPTOR), TAG_ISAPNP);
|
|
if (!d)
|
|
return STATUS_NO_MEMORY;
|
|
|
|
RtlZeroMemory(d, sizeof(ISAPNP_DESCRIPTOR));
|
|
|
|
d->Descriptor.Option = (UCHAR) Option;
|
|
|
|
*Descriptor = d;
|
|
|
|
CurrentEntry = LogicalDevice->Configuration.Flink;
|
|
while (CurrentEntry != &LogicalDevice->Configuration) {
|
|
List = CONTAINING_RECORD(
|
|
CurrentEntry, ISAPNP_CONFIGURATION_LIST, ListEntry);
|
|
|
|
if (List->Priority == Priority) {
|
|
|
|
LogicalDevice->ConfigurationSize += sizeof(IO_RESOURCE_DESCRIPTOR);
|
|
InsertTailList(&List->ListHead, &d->ListEntry);
|
|
LogicalDevice->CurrentDescriptorCount++;
|
|
if (LogicalDevice->DescriptorCount <
|
|
LogicalDevice->CurrentDescriptorCount) {
|
|
LogicalDevice->DescriptorCount =
|
|
LogicalDevice->CurrentDescriptorCount;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
}
|
|
|
|
Status = AddResourceList(LogicalDevice, Priority, &List);
|
|
if (NT_SUCCESS(Status)) {
|
|
LogicalDevice->ConfigurationSize += sizeof(IO_RESOURCE_LIST);
|
|
LogicalDevice->CurrentDescriptorCount = 0;
|
|
InsertTailList(&List->ListHead, &d->ListEntry);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*
|
|
* Add IRQ resource to resources list
|
|
*/
|
|
static NTSTATUS AddIrqResource(
|
|
PISAPNP_LOGICAL_DEVICE LogicalDevice,
|
|
ULONG Size,
|
|
ULONG Priority,
|
|
ULONG Option)
|
|
{
|
|
PISAPNP_DESCRIPTOR Descriptor;
|
|
UCHAR tmp[3];
|
|
ULONG irq, i, last = 0;
|
|
BOOLEAN found;
|
|
NTSTATUS Status;
|
|
|
|
Peek(tmp, Size);
|
|
|
|
irq = UCHAR2USHORT(tmp[0], tmp[0]);
|
|
|
|
DPRINT("IRQ bitmask: 0x%X\n", irq);
|
|
|
|
found = FALSE;
|
|
for (i = 0; i < 16; i++) {
|
|
if (!found && (irq & (1 << i))) {
|
|
last = i;
|
|
found = TRUE;
|
|
}
|
|
|
|
if ((found && !(irq & (1 << i))) || (irq & (1 << i) && (i == 15))) {
|
|
Status = AddResourceDescriptor(LogicalDevice,
|
|
Priority, Option, &Descriptor);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
Descriptor->Descriptor.Type = CmResourceTypeInterrupt;
|
|
Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
|
|
Descriptor->Descriptor.u.Interrupt.MinimumVector = last;
|
|
|
|
if ((irq & (1 << i)) && (i == 15))
|
|
Descriptor->Descriptor.u.Interrupt.MaximumVector = i;
|
|
else
|
|
Descriptor->Descriptor.u.Interrupt.MaximumVector = i - 1;
|
|
|
|
DPRINT("Found IRQ range %d - %d for logical device %d on card %d\n",
|
|
Descriptor->Descriptor.u.Interrupt.MinimumVector,
|
|
Descriptor->Descriptor.u.Interrupt.MaximumVector,
|
|
LogicalDevice->Number,
|
|
LogicalDevice->Card->CardId);
|
|
|
|
found = FALSE;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Add DMA resource to resources list
|
|
*/
|
|
static NTSTATUS AddDmaResource(
|
|
PISAPNP_LOGICAL_DEVICE LogicalDevice,
|
|
ULONG Size,
|
|
ULONG Priority,
|
|
ULONG Option)
|
|
{
|
|
PISAPNP_DESCRIPTOR Descriptor;
|
|
UCHAR tmp[2];
|
|
ULONG dma, flags, i, last = 0;
|
|
BOOLEAN found;
|
|
NTSTATUS Status;
|
|
|
|
Peek(tmp, Size);
|
|
|
|
dma = tmp[0];
|
|
flags = tmp[1];
|
|
|
|
DPRINT("DMA bitmask: 0x%X\n", dma);
|
|
|
|
found = FALSE;
|
|
for (i = 0; i < 8; i++) {
|
|
if (!found && (dma & (1 << i))) {
|
|
last = i;
|
|
found = TRUE;
|
|
}
|
|
|
|
if ((found && !(dma & (1 << i))) || (dma & (1 << i) && (i == 15))) {
|
|
Status = AddResourceDescriptor(LogicalDevice,
|
|
Priority, Option, &Descriptor);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
Descriptor->Descriptor.Type = CmResourceTypeDma;
|
|
Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
|
|
Descriptor->Descriptor.u.Dma.MinimumChannel = last;
|
|
|
|
if ((dma & (1 << i)) && (i == 15))
|
|
Descriptor->Descriptor.u.Dma.MaximumChannel = i;
|
|
else
|
|
Descriptor->Descriptor.u.Dma.MaximumChannel = i - 1;
|
|
|
|
/* FIXME: Parse flags */
|
|
|
|
DPRINT("Found DMA range %d - %d for logical device %d on card %d\n",
|
|
Descriptor->Descriptor.u.Dma.MinimumChannel,
|
|
Descriptor->Descriptor.u.Dma.MaximumChannel,
|
|
LogicalDevice->Number,
|
|
LogicalDevice->Card->CardId);
|
|
|
|
found = FALSE;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Add port resource to resources list
|
|
*/
|
|
static NTSTATUS AddIOPortResource(
|
|
PISAPNP_LOGICAL_DEVICE LogicalDevice,
|
|
ULONG Size,
|
|
ULONG Priority,
|
|
ULONG Option)
|
|
{
|
|
#if 0
|
|
DPRINT("I/O port: size 0x%X\n", Size);
|
|
Skip(Size);
|
|
#else
|
|
PISAPNP_DESCRIPTOR Descriptor;
|
|
UCHAR tmp[7];
|
|
NTSTATUS Status;
|
|
|
|
Peek(tmp, Size);
|
|
|
|
Status = AddResourceDescriptor(LogicalDevice,
|
|
Priority, Option, &Descriptor);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
Descriptor->Descriptor.Type = CmResourceTypePort;
|
|
Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
|
|
Descriptor->Descriptor.u.Port.Length = tmp[6];
|
|
/* FIXME: Parse flags */
|
|
Descriptor->Descriptor.u.Port.Alignment = 0;
|
|
Descriptor->Descriptor.u.Port.MinimumAddress.QuadPart = UCHAR2USHORT(tmp[1], tmp[2]);
|
|
Descriptor->Descriptor.u.Port.MaximumAddress.QuadPart = UCHAR2USHORT(tmp[4], tmp[4]);
|
|
|
|
DPRINT("Found I/O port range 0x%X - 0x%X for logical device %d on card %d\n",
|
|
Descriptor->Descriptor.u.Port.MinimumAddress,
|
|
Descriptor->Descriptor.u.Port.MaximumAddress,
|
|
LogicalDevice->Number,
|
|
LogicalDevice->Card->CardId);
|
|
#endif
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Add fixed port resource to resources list
|
|
*/
|
|
static NTSTATUS AddFixedIOPortResource(
|
|
PISAPNP_LOGICAL_DEVICE LogicalDevice,
|
|
ULONG Size,
|
|
ULONG Priority,
|
|
ULONG Option)
|
|
{
|
|
#if 0
|
|
DPRINT("Fixed I/O port: size 0x%X\n", Size);
|
|
Skip(Size);
|
|
#else
|
|
PISAPNP_DESCRIPTOR Descriptor;
|
|
UCHAR tmp[3];
|
|
NTSTATUS Status;
|
|
|
|
Peek(tmp, Size);
|
|
|
|
Status = AddResourceDescriptor(LogicalDevice,
|
|
Priority, Option, &Descriptor);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
Descriptor->Descriptor.Type = CmResourceTypePort;
|
|
Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
|
|
Descriptor->Descriptor.u.Port.Length = tmp[2];
|
|
Descriptor->Descriptor.u.Port.Alignment = 0;
|
|
Descriptor->Descriptor.u.Port.MinimumAddress.QuadPart = UCHAR2USHORT(tmp[0], tmp[1]);
|
|
Descriptor->Descriptor.u.Port.MaximumAddress.QuadPart = UCHAR2USHORT(tmp[0], tmp[1]);
|
|
|
|
DPRINT("Found fixed I/O port range 0x%X - 0x%X for logical device %d on card %d\n",
|
|
Descriptor->Descriptor.u.Port.MinimumAddress,
|
|
Descriptor->Descriptor.u.Port.MaximumAddress,
|
|
LogicalDevice->Number,
|
|
LogicalDevice->Card->CardId);
|
|
#endif
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Add memory resource to resources list
|
|
*/
|
|
static NTSTATUS AddMemoryResource(
|
|
PISAPNP_LOGICAL_DEVICE LogicalDevice,
|
|
ULONG Size,
|
|
ULONG Priority,
|
|
ULONG Option)
|
|
{
|
|
#if 0
|
|
DPRINT("Memory range: size 0x%X\n", Size);
|
|
Skip(Size);
|
|
#else
|
|
PISAPNP_DESCRIPTOR Descriptor;
|
|
UCHAR tmp[9];
|
|
NTSTATUS Status;
|
|
|
|
Peek(tmp, Size);
|
|
|
|
Status = AddResourceDescriptor(LogicalDevice,
|
|
Priority, Option, &Descriptor);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
Descriptor->Descriptor.Type = CmResourceTypeMemory;
|
|
Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
|
|
Descriptor->Descriptor.u.Memory.Length = UCHAR2USHORT(tmp[7], tmp[8]) << 8;
|
|
Descriptor->Descriptor.u.Memory.Alignment = UCHAR2USHORT(tmp[5], tmp[6]);
|
|
Descriptor->Descriptor.u.Memory.MinimumAddress.QuadPart = UCHAR2USHORT(tmp[1], tmp[2]) << 8;
|
|
Descriptor->Descriptor.u.Memory.MaximumAddress.QuadPart = UCHAR2USHORT(tmp[3], tmp[4]) << 8;
|
|
|
|
DPRINT("Found memory range 0x%X - 0x%X for logical device %d on card %d\n",
|
|
Descriptor->Descriptor.u.Memory.MinimumAddress,
|
|
Descriptor->Descriptor.u.Memory.MaximumAddress,
|
|
LogicalDevice->Number,
|
|
LogicalDevice->Card->CardId);
|
|
#endif
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Add 32-bit memory resource to resources list
|
|
*/
|
|
static NTSTATUS AddMemory32Resource(
|
|
PISAPNP_LOGICAL_DEVICE LogicalDevice,
|
|
ULONG Size,
|
|
ULONG Priority,
|
|
ULONG Option)
|
|
{
|
|
#if 0
|
|
DPRINT("Memory32 range: size 0x%X\n", Size);
|
|
Skip(Size);
|
|
#else
|
|
PISAPNP_DESCRIPTOR Descriptor;
|
|
UCHAR tmp[17];
|
|
NTSTATUS Status;
|
|
|
|
Peek(tmp, Size);
|
|
|
|
Status = AddResourceDescriptor(LogicalDevice,
|
|
Priority, Option, &Descriptor);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
Descriptor->Descriptor.Type = CmResourceTypeMemory;
|
|
Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
|
|
Descriptor->Descriptor.u.Memory.Length =
|
|
UCHAR2ULONG(tmp[13], tmp[14], tmp[15], tmp[16]);
|
|
Descriptor->Descriptor.u.Memory.Alignment =
|
|
UCHAR2ULONG(tmp[9], tmp[10], tmp[11], tmp[12]);
|
|
Descriptor->Descriptor.u.Memory.MinimumAddress.QuadPart =
|
|
UCHAR2ULONG(tmp[1], tmp[2], tmp[3], tmp[4]);
|
|
Descriptor->Descriptor.u.Memory.MaximumAddress.QuadPart =
|
|
UCHAR2ULONG(tmp[5], tmp[6], tmp[7], tmp[8]);
|
|
|
|
DPRINT("Found memory32 range 0x%X - 0x%X for logical device %d on card %d\n",
|
|
Descriptor->Descriptor.u.Memory.MinimumAddress,
|
|
Descriptor->Descriptor.u.Memory.MaximumAddress,
|
|
LogicalDevice->Number,
|
|
LogicalDevice->Card->CardId);
|
|
#endif
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Add 32-bit fixed memory resource to resources list
|
|
*/
|
|
static NTSTATUS AddFixedMemory32Resource(
|
|
PISAPNP_LOGICAL_DEVICE LogicalDevice,
|
|
ULONG Size,
|
|
ULONG Priority,
|
|
ULONG Option)
|
|
{
|
|
#if 0
|
|
DPRINT("Memory32 range: size 0x%X\n", Size);
|
|
Skip(Size);
|
|
#else
|
|
PISAPNP_DESCRIPTOR Descriptor;
|
|
UCHAR tmp[17];
|
|
NTSTATUS Status;
|
|
|
|
Peek(tmp, Size);
|
|
|
|
Status = AddResourceDescriptor(LogicalDevice,
|
|
Priority, Option, &Descriptor);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
Descriptor->Descriptor.Type = CmResourceTypeMemory;
|
|
Descriptor->Descriptor.ShareDisposition = CmResourceShareDeviceExclusive;
|
|
Descriptor->Descriptor.u.Memory.Length =
|
|
UCHAR2ULONG(tmp[9], tmp[10], tmp[11], tmp[12]);
|
|
Descriptor->Descriptor.u.Memory.Alignment =
|
|
UCHAR2ULONG(tmp[5], tmp[6], tmp[7], tmp[8]);
|
|
Descriptor->Descriptor.u.Memory.MinimumAddress.QuadPart =
|
|
UCHAR2ULONG(tmp[1], tmp[2], tmp[3], tmp[4]);
|
|
Descriptor->Descriptor.u.Memory.MaximumAddress.QuadPart =
|
|
UCHAR2ULONG(tmp[1], tmp[2], tmp[3], tmp[4]);
|
|
|
|
DPRINT("Found fixed memory32 range 0x%X - 0x%X for logical device %d on card %d\n",
|
|
Descriptor->Descriptor.u.Memory.MinimumAddress,
|
|
Descriptor->Descriptor.u.Memory.MaximumAddress,
|
|
LogicalDevice->Number,
|
|
LogicalDevice->Card->CardId);
|
|
#endif
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* Parse logical device tag
|
|
*/
|
|
static PISAPNP_LOGICAL_DEVICE ParseLogicalDevice(
|
|
PISAPNP_DEVICE_EXTENSION DeviceExtension,
|
|
PISAPNP_CARD Card,
|
|
ULONG Size,
|
|
USHORT Number)
|
|
{
|
|
UCHAR tmp[6];
|
|
PISAPNP_LOGICAL_DEVICE LogicalDevice;
|
|
|
|
DPRINT("Card %d Number %d\n", Card->CardId, Number);
|
|
|
|
Peek(tmp, Size);
|
|
|
|
LogicalDevice = (PISAPNP_LOGICAL_DEVICE)ExAllocatePoolWithTag(
|
|
PagedPool, sizeof(ISAPNP_LOGICAL_DEVICE), TAG_ISAPNP);
|
|
if (!LogicalDevice)
|
|
return NULL;
|
|
|
|
RtlZeroMemory(LogicalDevice, sizeof(ISAPNP_LOGICAL_DEVICE));
|
|
|
|
LogicalDevice->Number = Number;
|
|
LogicalDevice->VendorId = UCHAR2USHORT(tmp[0], tmp[1]);
|
|
LogicalDevice->DeviceId = UCHAR2USHORT(tmp[2], tmp[3]);
|
|
LogicalDevice->Regs = tmp[4];
|
|
LogicalDevice->Card = Card;
|
|
if (Size > 5)
|
|
LogicalDevice->Regs |= tmp[5] << 8;
|
|
|
|
InitializeListHead(&LogicalDevice->Configuration);
|
|
|
|
ExInterlockedInsertTailList(&Card->LogicalDevices,
|
|
&LogicalDevice->CardListEntry,
|
|
&Card->LogicalDevicesLock);
|
|
|
|
ExInterlockedInsertTailList(&DeviceExtension->DeviceListHead,
|
|
&LogicalDevice->DeviceListEntry,
|
|
&DeviceExtension->GlobalListLock);
|
|
|
|
DeviceExtension->DeviceListCount++;
|
|
|
|
return LogicalDevice;
|
|
}
|
|
|
|
|
|
/*
|
|
* Parse resource map for logical device
|
|
*/
|
|
static BOOLEAN CreateLogicalDevice(PISAPNP_DEVICE_EXTENSION DeviceExtension,
|
|
PISAPNP_CARD Card, USHORT Size)
|
|
{
|
|
ULONG number = 0, skip = 0, compat = 0;
|
|
UCHAR type, tmp[17];
|
|
PISAPNP_LOGICAL_DEVICE LogicalDevice;
|
|
BOOLEAN Small;
|
|
ULONG Priority = 0;
|
|
ULONG Option = IO_RESOURCE_REQUIRED;
|
|
|
|
DPRINT("Card %d Size %d\n", Card->CardId, Size);
|
|
|
|
LogicalDevice = ParseLogicalDevice(DeviceExtension, Card, Size, (USHORT) number++);
|
|
if (!LogicalDevice)
|
|
return FALSE;
|
|
|
|
while (TRUE) {
|
|
if (!ReadTag(&type, &Size, &Small))
|
|
return FALSE;
|
|
|
|
if (skip && !(Small && ((type == ISAPNP_SRIN_LDEVICE_ID)
|
|
|| (type == ISAPNP_SRIN_END_TAG))))
|
|
goto skip;
|
|
|
|
if (Small) {
|
|
switch (type) {
|
|
case ISAPNP_SRIN_LDEVICE_ID:
|
|
if ((Size >= 5) && (Size <= 6)) {
|
|
LogicalDevice = ParseLogicalDevice(
|
|
DeviceExtension, Card, Size, (USHORT)number++);
|
|
if (!LogicalDevice)
|
|
return FALSE;
|
|
Size = 0;
|
|
skip = 0;
|
|
} else {
|
|
skip = 1;
|
|
}
|
|
Priority = 0;
|
|
Option = IO_RESOURCE_REQUIRED;
|
|
compat = 0;
|
|
break;
|
|
|
|
case ISAPNP_SRIN_CDEVICE_ID:
|
|
if ((Size == 4) && (compat < MAX_COMPATIBLE_ID)) {
|
|
Peek(tmp, 4);
|
|
LogicalDevice->CVendorId[compat] = UCHAR2USHORT(tmp[0], tmp[1]);
|
|
LogicalDevice->CDeviceId[compat] = UCHAR2USHORT(tmp[2], tmp[3]);
|
|
compat++;
|
|
Size = 0;
|
|
}
|
|
break;
|
|
|
|
case ISAPNP_SRIN_IRQ_FORMAT:
|
|
if ((Size < 2) || (Size > 3))
|
|
goto skip;
|
|
AddIrqResource(LogicalDevice, Size, Priority, Option);
|
|
Size = 0;
|
|
break;
|
|
|
|
case ISAPNP_SRIN_DMA_FORMAT:
|
|
if (Size != 2)
|
|
goto skip;
|
|
AddDmaResource(LogicalDevice, Size, Priority, Option);
|
|
Size = 0;
|
|
break;
|
|
|
|
case ISAPNP_SRIN_START_DFUNCTION:
|
|
if (Size > 1)
|
|
goto skip;
|
|
|
|
if (Size > 0) {
|
|
Peek(tmp, Size);
|
|
Priority = tmp[0];
|
|
Size = 0;
|
|
/* FIXME: Maybe use IO_RESOURCE_PREFERRED for some */
|
|
Option = IO_RESOURCE_ALTERNATIVE;
|
|
} else {
|
|
Priority = 0;
|
|
Option = IO_RESOURCE_ALTERNATIVE;
|
|
}
|
|
|
|
DPRINT(" Start priority %d \n", Priority);
|
|
|
|
LogicalDevice->CurrentDescriptorCount = 0;
|
|
|
|
break;
|
|
|
|
case ISAPNP_SRIN_END_DFUNCTION:
|
|
|
|
DPRINT(" End priority %d \n", Priority);
|
|
|
|
if (Size != 0)
|
|
goto skip;
|
|
Priority = 0;
|
|
Option = IO_RESOURCE_REQUIRED;
|
|
LogicalDevice->CurrentDescriptorCount = 0;
|
|
break;
|
|
|
|
case ISAPNP_SRIN_IO_DESCRIPTOR:
|
|
if (Size != 7)
|
|
goto skip;
|
|
AddIOPortResource(LogicalDevice, Size, Priority, Option);
|
|
Size = 0;
|
|
break;
|
|
|
|
case ISAPNP_SRIN_FL_IO_DESCRIPOTOR:
|
|
if (Size != 3)
|
|
goto skip;
|
|
AddFixedIOPortResource(LogicalDevice, Size, Priority, Option);
|
|
Size = 0;
|
|
break;
|
|
|
|
case ISAPNP_SRIN_VENDOR_DEFINED:
|
|
break;
|
|
|
|
case ISAPNP_SRIN_END_TAG:
|
|
if (Size > 0)
|
|
Skip(Size);
|
|
return FALSE;
|
|
|
|
default:
|
|
DPRINT("Ignoring small tag of type 0x%X for logical device %d on card %d\n",
|
|
type, LogicalDevice->Number, Card->CardId);
|
|
}
|
|
} else {
|
|
switch (type) {
|
|
case ISAPNP_LRIN_MEMORY_RANGE:
|
|
if (Size != 9)
|
|
goto skip;
|
|
AddMemoryResource(LogicalDevice, Size, Priority, Option);
|
|
Size = 0;
|
|
break;
|
|
|
|
case ISAPNP_LRIN_ID_STRING_ANSI:
|
|
ParseAnsiName(&LogicalDevice->Name, &Size);
|
|
break;
|
|
|
|
case ISAPNP_LRIN_ID_STRING_UNICODE:
|
|
break;
|
|
|
|
case ISAPNP_LRIN_VENDOR_DEFINED:
|
|
break;
|
|
|
|
case ISAPNP_LRIN_MEMORY_RANGE32:
|
|
if (Size != 17)
|
|
goto skip;
|
|
AddMemory32Resource(LogicalDevice, Size, Priority, Option);
|
|
Size = 0;
|
|
break;
|
|
|
|
case ISAPNP_LRIN_FL_MEMORY_RANGE32:
|
|
if (Size != 17)
|
|
goto skip;
|
|
AddFixedMemory32Resource(LogicalDevice, Size, Priority, Option);
|
|
Size = 0;
|
|
break;
|
|
|
|
default:
|
|
DPRINT("Ignoring large tag of type 0x%X for logical device %d on card %d\n",
|
|
type, LogicalDevice->Number, Card->CardId);
|
|
}
|
|
}
|
|
skip:
|
|
if (Size > 0)
|
|
Skip(Size);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Parse resource map for ISA PnP card
|
|
*/
|
|
static BOOLEAN ParseResourceMap(PISAPNP_DEVICE_EXTENSION DeviceExtension,
|
|
PISAPNP_CARD Card)
|
|
{
|
|
UCHAR type, tmp[17];
|
|
USHORT size;
|
|
BOOLEAN Small;
|
|
|
|
DPRINT("Card %d\n", Card->CardId);
|
|
|
|
while (TRUE) {
|
|
if (!ReadTag(&type, &size, &Small))
|
|
return FALSE;
|
|
|
|
if (Small) {
|
|
switch (type) {
|
|
case ISAPNP_SRIN_VERSION:
|
|
if (size != 2)
|
|
goto skip;
|
|
Peek(tmp, 2);
|
|
Card->PNPVersion = tmp[0];
|
|
Card->ProductVersion = tmp[1];
|
|
size = 0;
|
|
break;
|
|
|
|
case ISAPNP_SRIN_LDEVICE_ID:
|
|
if ((size >= 5) && (size <= 6)) {
|
|
if (!CreateLogicalDevice(DeviceExtension, Card, size))
|
|
return FALSE;
|
|
size = 0;
|
|
}
|
|
break;
|
|
|
|
case ISAPNP_SRIN_CDEVICE_ID:
|
|
/* FIXME: Parse compatible IDs */
|
|
break;
|
|
|
|
case ISAPNP_SRIN_END_TAG:
|
|
if (size > 0)
|
|
Skip(size);
|
|
return TRUE;
|
|
|
|
default:
|
|
DPRINT("Ignoring small tag Type 0x%X for Card %d\n", type, Card->CardId);
|
|
}
|
|
} else {
|
|
switch (type) {
|
|
case ISAPNP_LRIN_ID_STRING_ANSI:
|
|
ParseAnsiName(&Card->Name, &size);
|
|
break;
|
|
|
|
default:
|
|
DPRINT("Ignoring large tag Type 0x%X for Card %d\n",
|
|
type, Card->CardId);
|
|
}
|
|
}
|
|
skip:
|
|
if (size > 0)
|
|
Skip(size);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Compute ISA PnP checksum for first eight bytes
|
|
*/
|
|
static UCHAR Checksum(PUCHAR data)
|
|
{
|
|
ULONG i, j;
|
|
UCHAR checksum = 0x6a, bit, b;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
b = data[i];
|
|
for (j = 0; j < 8; j++) {
|
|
bit = 0;
|
|
if (b & (1 << j))
|
|
bit = 1;
|
|
checksum = ((((checksum ^ (checksum >> 1)) &
|
|
0x01) ^ bit) << 7) | (checksum >> 1);
|
|
}
|
|
}
|
|
return checksum;
|
|
}
|
|
|
|
|
|
/*
|
|
* Build a resource list for a logical ISA PnP device
|
|
*/
|
|
static NTSTATUS BuildResourceList(PISAPNP_LOGICAL_DEVICE LogicalDevice,
|
|
PIO_RESOURCE_LIST DestinationList,
|
|
ULONG Priority)
|
|
{
|
|
PLIST_ENTRY CurrentEntry, Entry;
|
|
PISAPNP_CONFIGURATION_LIST List;
|
|
PISAPNP_DESCRIPTOR Descriptor;
|
|
ULONG i;
|
|
|
|
if (IsListEmpty(&LogicalDevice->Configuration))
|
|
return STATUS_NOT_FOUND;
|
|
|
|
CurrentEntry = LogicalDevice->Configuration.Flink;
|
|
while (CurrentEntry != &LogicalDevice->Configuration) {
|
|
List = CONTAINING_RECORD(
|
|
CurrentEntry, ISAPNP_CONFIGURATION_LIST, ListEntry);
|
|
|
|
if (List->Priority == Priority) {
|
|
|
|
DPRINT("Logical device %d DestinationList %p\n",
|
|
LogicalDevice->Number,
|
|
DestinationList);
|
|
|
|
DestinationList->Version = 1;
|
|
DestinationList->Revision = 1;
|
|
DestinationList->Count = LogicalDevice->DescriptorCount;
|
|
|
|
i = 0;
|
|
Entry = List->ListHead.Flink;
|
|
while (Entry != &List->ListHead) {
|
|
Descriptor = CONTAINING_RECORD(
|
|
Entry, ISAPNP_DESCRIPTOR, ListEntry);
|
|
|
|
DPRINT("Logical device %d Destination %p(%d)\n",
|
|
LogicalDevice->Number,
|
|
&DestinationList->Descriptors[i],
|
|
i);
|
|
|
|
RtlCopyMemory(&DestinationList->Descriptors[i],
|
|
&Descriptor->Descriptor,
|
|
sizeof(IO_RESOURCE_DESCRIPTOR));
|
|
|
|
i++;
|
|
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
RemoveEntryList(&List->ListEntry);
|
|
|
|
ExFreePool(List);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
}
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
|
|
/*
|
|
* Build resource lists for a logical ISA PnP device
|
|
*/
|
|
static NTSTATUS BuildResourceLists(PISAPNP_LOGICAL_DEVICE LogicalDevice)
|
|
{
|
|
ULONG ListSize;
|
|
ULONG Priority;
|
|
ULONG SingleListSize;
|
|
PIO_RESOURCE_LIST p;
|
|
NTSTATUS Status;
|
|
|
|
ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST)
|
|
- sizeof(IO_RESOURCE_LIST)
|
|
+ LogicalDevice->ConfigurationSize;
|
|
|
|
DPRINT("Logical device %d ListSize 0x%X ConfigurationSize 0x%X DescriptorCount %d\n",
|
|
LogicalDevice->Number, ListSize,
|
|
LogicalDevice->ConfigurationSize,
|
|
LogicalDevice->DescriptorCount);
|
|
|
|
LogicalDevice->ResourceLists =
|
|
(PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePoolWithTag(
|
|
PagedPool, ListSize, TAG_ISAPNP);
|
|
if (!LogicalDevice->ResourceLists)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
RtlZeroMemory(LogicalDevice->ResourceLists, ListSize);
|
|
|
|
SingleListSize = sizeof(IO_RESOURCE_LIST) +
|
|
(LogicalDevice->DescriptorCount - 1) *
|
|
sizeof(IO_RESOURCE_DESCRIPTOR);
|
|
|
|
DPRINT("SingleListSize %d\n", SingleListSize);
|
|
|
|
Priority = 0;
|
|
p = &LogicalDevice->ResourceLists->List[0];
|
|
do {
|
|
Status = BuildResourceList(LogicalDevice, p, Priority);
|
|
if (NT_SUCCESS(Status)) {
|
|
p = (PIO_RESOURCE_LIST)((ULONG_PTR)p + SingleListSize);
|
|
Priority++;
|
|
}
|
|
} while (Status != STATUS_NOT_FOUND);
|
|
|
|
LogicalDevice->ResourceLists->ListSize = ListSize;
|
|
LogicalDevice->ResourceLists->AlternativeLists = Priority + 1;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* Build resource lists for a ISA PnP card
|
|
*/
|
|
static NTSTATUS BuildResourceListsForCard(PISAPNP_CARD Card)
|
|
{
|
|
PISAPNP_LOGICAL_DEVICE LogicalDevice;
|
|
PLIST_ENTRY CurrentEntry;
|
|
NTSTATUS Status;
|
|
|
|
CurrentEntry = Card->LogicalDevices.Flink;
|
|
while (CurrentEntry != &Card->LogicalDevices) {
|
|
LogicalDevice = CONTAINING_RECORD(
|
|
CurrentEntry, ISAPNP_LOGICAL_DEVICE, CardListEntry);
|
|
Status = BuildResourceLists(LogicalDevice);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* Build resource lists for all present ISA PnP cards
|
|
*/
|
|
static NTSTATUS BuildResourceListsForAll(
|
|
PISAPNP_DEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
PLIST_ENTRY CurrentEntry;
|
|
PISAPNP_CARD Card;
|
|
NTSTATUS Status;
|
|
|
|
CurrentEntry = DeviceExtension->CardListHead.Flink;
|
|
while (CurrentEntry != &DeviceExtension->CardListHead) {
|
|
Card = CONTAINING_RECORD(
|
|
CurrentEntry, ISAPNP_CARD, ListEntry);
|
|
Status = BuildResourceListsForCard(Card);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* Build device list for all present ISA PnP cards
|
|
*/
|
|
static NTSTATUS BuildDeviceList(PISAPNP_DEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
ULONG csn;
|
|
UCHAR header[9], checksum;
|
|
PISAPNP_CARD Card;
|
|
|
|
DPRINT("Called\n");
|
|
|
|
SendWait();
|
|
SendKey();
|
|
for (csn = 1; csn <= 10; csn++) {
|
|
SendWake((UCHAR)csn);
|
|
Peek(header, 9);
|
|
checksum = Checksum(header);
|
|
|
|
if (checksum == 0x00 || checksum != header[8]) /* Invalid CSN */
|
|
continue;
|
|
|
|
DPRINT("VENDOR: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
header[0], header[1], header[2], header[3],
|
|
header[4], header[5], header[6], header[7], header[8]);
|
|
|
|
Card = (PISAPNP_CARD)ExAllocatePoolWithTag(
|
|
PagedPool, sizeof(ISAPNP_CARD), TAG_ISAPNP);
|
|
if (!Card)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
RtlZeroMemory(Card, sizeof(ISAPNP_CARD));
|
|
|
|
Card->CardId = (USHORT) csn;
|
|
Card->VendorId = (header[1] << 8) | header[0];
|
|
Card->DeviceId = (header[3] << 8) | header[2];
|
|
Card->Serial = (header[7] << 24) | (header[6] << 16) | (header[5] << 8) | header[4];
|
|
|
|
InitializeListHead(&Card->LogicalDevices);
|
|
KeInitializeSpinLock(&Card->LogicalDevicesLock);
|
|
|
|
ParseResourceMap(DeviceExtension, Card);
|
|
|
|
ExInterlockedInsertTailList(&DeviceExtension->CardListHead,
|
|
&Card->ListEntry,
|
|
&DeviceExtension->GlobalListLock);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
static NTSTATUS
|
|
ISAPNPQueryBusRelations(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PISAPNP_DEVICE_EXTENSION DeviceExtension;
|
|
PISAPNP_LOGICAL_DEVICE LogicalDevice;
|
|
PDEVICE_RELATIONS Relations;
|
|
PLIST_ENTRY CurrentEntry;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ULONG Size;
|
|
ULONG i;
|
|
|
|
DPRINT("Called\n");
|
|
|
|
DeviceExtension = (PISAPNP_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
if (Irp->IoStatus.Information) {
|
|
/* FIXME: Another bus driver has already created a DEVICE_RELATIONS
|
|
structure so we must merge this structure with our own */
|
|
}
|
|
|
|
Size = sizeof(DEVICE_RELATIONS) + sizeof(Relations->Objects) *
|
|
(DeviceExtension->DeviceListCount - 1);
|
|
Relations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(PagedPool, Size, TAG_ISAPNP);
|
|
if (!Relations)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
Relations->Count = DeviceExtension->DeviceListCount;
|
|
|
|
i = 0;
|
|
CurrentEntry = DeviceExtension->DeviceListHead.Flink;
|
|
while (CurrentEntry != &DeviceExtension->DeviceListHead) {
|
|
LogicalDevice = CONTAINING_RECORD(
|
|
CurrentEntry, ISAPNP_LOGICAL_DEVICE, DeviceListEntry);
|
|
|
|
if (!LogicalDevice->Pdo) {
|
|
/* Create a physical device object for the
|
|
device as it does not already have one */
|
|
Status = IoCreateDevice(DeviceObject->DriverObject, 0,
|
|
NULL, FILE_DEVICE_CONTROLLER, 0, FALSE, &LogicalDevice->Pdo);
|
|
if (!NT_SUCCESS(Status)) {
|
|
DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
|
|
ExFreePool(Relations);
|
|
return Status;
|
|
}
|
|
|
|
LogicalDevice->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
|
|
}
|
|
|
|
/* Reference the physical device object. The PnP manager
|
|
will dereference it again when it is no longer needed */
|
|
ObReferenceObject(LogicalDevice->Pdo);
|
|
|
|
Relations->Objects[i] = LogicalDevice->Pdo;
|
|
|
|
i++;
|
|
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
}
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)Relations;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
static NTSTATUS
|
|
ISAPNPQueryDeviceRelations(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PISAPNP_DEVICE_EXTENSION DeviceExtension;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("Called\n");
|
|
|
|
DeviceExtension = (PISAPNP_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
if (DeviceExtension->State == dsStopped)
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
switch (IrpSp->Parameters.QueryDeviceRelations.Type) {
|
|
case BusRelations:
|
|
Status = ISAPNPQueryBusRelations(DeviceObject, Irp, IrpSp);
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
static NTSTATUS
|
|
ISAPNPStartDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PISAPNP_DEVICE_EXTENSION DeviceExtension;
|
|
NTSTATUS Status;
|
|
ULONG NumCards;
|
|
|
|
DPRINT("Called\n");
|
|
|
|
DeviceExtension = (PISAPNP_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
if (DeviceExtension->State == dsStarted)
|
|
return STATUS_SUCCESS;
|
|
|
|
NumCards = IsolatePnPCards();
|
|
|
|
DPRINT("Number of ISA PnP cards found: %d\n", NumCards);
|
|
|
|
Status = BuildDeviceList(DeviceExtension);
|
|
if (!NT_SUCCESS(Status)) {
|
|
DPRINT("BuildDeviceList() failed with status 0x%X\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
Status = BuildResourceListsForAll(DeviceExtension);
|
|
if (!NT_SUCCESS(Status)) {
|
|
DPRINT("BuildResourceListsForAll() failed with status 0x%X\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
DeviceExtension->State = dsStarted;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
static NTSTATUS
|
|
ISAPNPStopDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PISAPNP_DEVICE_EXTENSION DeviceExtension;
|
|
|
|
DPRINT("Called\n");
|
|
|
|
DeviceExtension = (PISAPNP_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
if (DeviceExtension->State != dsStopped) {
|
|
/* FIXME: Stop device */
|
|
DeviceExtension->State = dsStopped;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
static DRIVER_DISPATCH ISAPNPDispatchOpenClose;
|
|
static NTSTATUS
|
|
NTAPI
|
|
ISAPNPDispatchOpenClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
DPRINT("Called\n");
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = FILE_OPENED;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static DRIVER_DISPATCH ISAPNPDispatchReadWrite;
|
|
static NTSTATUS
|
|
NTAPI
|
|
ISAPNPDispatchReadWrite(
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
DPRINT("Called\n");
|
|
|
|
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
static DRIVER_DISPATCH ISAPNPDispatchDeviceControl;
|
|
static NTSTATUS
|
|
NTAPI
|
|
ISAPNPDispatchDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("Called\n");
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
default:
|
|
DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
DPRINT("Leaving. Status 0x%X\n", Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
static DRIVER_DISPATCH ISAPNPControl;
|
|
static NTSTATUS
|
|
NTAPI
|
|
ISAPNPControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("Called\n");
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
switch (IrpSp->MinorFunction) {
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
Status = ISAPNPQueryDeviceRelations(DeviceObject, Irp, IrpSp);
|
|
break;
|
|
|
|
case IRP_MN_START_DEVICE:
|
|
Status = ISAPNPStartDevice(DeviceObject, Irp, IrpSp);
|
|
break;
|
|
|
|
case IRP_MN_STOP_DEVICE:
|
|
Status = ISAPNPStopDevice(DeviceObject, Irp, IrpSp);
|
|
break;
|
|
|
|
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
|
|
/* Nothing to do here */
|
|
DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
|
|
Status = Irp->IoStatus.Status;
|
|
break;
|
|
|
|
default:
|
|
DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
DPRINT("Leaving. Status 0x%X\n", Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
static NTSTATUS
|
|
NTAPI
|
|
ISAPNPAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject)
|
|
{
|
|
PISAPNP_DEVICE_EXTENSION DeviceExtension;
|
|
PDEVICE_OBJECT Fdo;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("Called\n");
|
|
|
|
Status = IoCreateDevice(DriverObject, sizeof(ISAPNP_DEVICE_EXTENSION),
|
|
NULL, FILE_DEVICE_BUS_EXTENDER, FILE_DEVICE_SECURE_OPEN, TRUE, &Fdo);
|
|
if (!NT_SUCCESS(Status)) {
|
|
DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
DeviceExtension = (PISAPNP_DEVICE_EXTENSION)Fdo->DeviceExtension;
|
|
|
|
DeviceExtension->Pdo = PhysicalDeviceObject;
|
|
|
|
DeviceExtension->Ldo =
|
|
IoAttachDeviceToDeviceStack(Fdo, PhysicalDeviceObject);
|
|
|
|
InitializeListHead(&DeviceExtension->CardListHead);
|
|
InitializeListHead(&DeviceExtension->DeviceListHead);
|
|
DeviceExtension->DeviceListCount = 0;
|
|
KeInitializeSpinLock(&DeviceExtension->GlobalListLock);
|
|
|
|
DeviceExtension->State = dsStopped;
|
|
|
|
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
DPRINT("Done AddDevice\n");
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath)
|
|
{
|
|
DbgPrint("ISA Plug and Play Bus Driver\n");
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = ISAPNPDispatchOpenClose;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = ISAPNPDispatchOpenClose;
|
|
DriverObject->MajorFunction[IRP_MJ_READ] = ISAPNPDispatchReadWrite;
|
|
DriverObject->MajorFunction[IRP_MJ_WRITE] = ISAPNPDispatchReadWrite;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ISAPNPDispatchDeviceControl;
|
|
DriverObject->MajorFunction[IRP_MJ_PNP] = ISAPNPControl;
|
|
DriverObject->DriverExtension->AddDevice = ISAPNPAddDevice;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* EOF */
|