📄 isapnp.c
字号:
/* $Id: isapnp.c 27433 2007-07-06 20:25:30Z cwittich $
*
* 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 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 FindNextReadPort(VOID)
{
ULONG Port;
Port = (ULONG)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 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;
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)IsaPnPReadPort);
KeStallExecutionProcessor(1000);
WriteAddress(0x01);
KeStallExecutionProcessor(1000);
goto next;
}
if (iteration == 1) {
IsaPnPReadPort += READ_DATA_PORT_STEP;
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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -