mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
680 lines
16 KiB
680 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
devres.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the high level device resources support routines.
|
|
|
|
Author:
|
|
|
|
Shie-Lin Tzong (shielint) July-27-1995
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "busp.h"
|
|
#include "pnpisa.h"
|
|
#include "pbios.h"
|
|
|
|
#define IDBG 0
|
|
|
|
#pragma alloc_text(INIT,PipGetCardIdentifier)
|
|
#pragma alloc_text(INIT,PipGetFunctionIdentifier)
|
|
#pragma alloc_text(INIT,PipGetCompatibleDeviceId)
|
|
#pragma alloc_text(INIT,PipQueryDeviceId)
|
|
#pragma alloc_text(INIT,PipQueryDeviceUniqueId)
|
|
#pragma alloc_text(INIT,PipQueryDeviceResources)
|
|
#pragma alloc_text(INIT,PipQueryDeviceResourceRequirements)
|
|
#pragma alloc_text(INIT,PipSetDeviceResources)
|
|
|
|
NTSTATUS
|
|
PipGetCardIdentifier (
|
|
PUCHAR CardData,
|
|
PWCHAR *Buffer,
|
|
PULONG BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the identifier for a pnpisa card.
|
|
|
|
Arguments:
|
|
|
|
CardData - supplies a pointer to the pnp isa device data.
|
|
|
|
Buffer - supplies a pointer to variable to receive a pointer to the Id.
|
|
|
|
BufferLength - supplies a pointer to a variable to receive the size of the id buffer.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
UCHAR tag;
|
|
LONG size, length;
|
|
UNICODE_STRING unicodeString;
|
|
ANSI_STRING ansiString;
|
|
PCHAR ansiBuffer;
|
|
|
|
*Buffer = NULL;
|
|
*BufferLength = 0;
|
|
|
|
tag = *CardData;
|
|
|
|
//
|
|
// Make sure CardData does *NOT* point to a Logical Device Id tag
|
|
//
|
|
|
|
if ((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID) {
|
|
DbgPrint("PipGetCardIdentifier: CardData is at a Logical Id tag\n");
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Find the resource descriptor which describle identifier string
|
|
//
|
|
|
|
do {
|
|
|
|
//
|
|
// Do we find the identifer resource tag?
|
|
//
|
|
|
|
if (tag == TAG_ANSI_ID) {
|
|
CardData++;
|
|
length = *(PUSHORT)CardData;
|
|
CardData += 2;
|
|
ansiBuffer = (PCHAR)ExAllocatePool(PagedPool, length+1);
|
|
if (ansiBuffer == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
RtlMoveMemory(ansiBuffer, CardData, length);
|
|
ansiBuffer[length] = 0;
|
|
RtlInitAnsiString(&ansiString, ansiBuffer);
|
|
RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
|
|
ExFreePool(ansiBuffer);
|
|
*Buffer = unicodeString.Buffer;
|
|
*BufferLength = unicodeString.Length + sizeof(WCHAR);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Determine the size of the BIOS resource descriptor and
|
|
// advance to next resource descriptor.
|
|
//
|
|
|
|
if (!(tag & LARGE_RESOURCE_TAG)) {
|
|
size = (USHORT)(tag & SMALL_TAG_SIZE_MASK);
|
|
size += 1; // length of small tag
|
|
} else {
|
|
size = *(PUSHORT)(CardData + 1);
|
|
size += 3; // length of large tag
|
|
}
|
|
|
|
CardData += size;
|
|
tag = *CardData;
|
|
|
|
} while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID));
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PipGetFunctionIdentifier (
|
|
PUCHAR DeviceData,
|
|
PWCHAR *Buffer,
|
|
PULONG BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the desired pnp isa identifier for the specified
|
|
DeviceData/LogicalFunction. The Identifier for a logical function is
|
|
optional. If no Identifier available , Buffer is set to NULL.
|
|
|
|
Arguments:
|
|
|
|
DeviceData - supplies a pointer to the pnp isa device data.
|
|
|
|
Buffer - supplies a pointer to variable to receive a pointer to the Id.
|
|
|
|
BufferLength - supplies a pointer to a variable to receive the size of the id buffer.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
UCHAR tag;
|
|
LONG size, length;
|
|
UNICODE_STRING unicodeString;
|
|
ANSI_STRING ansiString;
|
|
PCHAR ansiBuffer;
|
|
|
|
*Buffer = NULL;
|
|
*BufferLength = 0;
|
|
|
|
tag = *DeviceData;
|
|
|
|
#if DBG
|
|
|
|
//
|
|
// Make sure device data points to Logical Device Id tag
|
|
//
|
|
|
|
if ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID) {
|
|
DbgPrint("PipGetFunctionIdentifier: DeviceData is not at a Logical Id tag\n");
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Skip all the resource descriptors to find compatible Id descriptor
|
|
//
|
|
|
|
do {
|
|
|
|
//
|
|
// Determine the size of the BIOS resource descriptor and
|
|
// advance to next resource descriptor.
|
|
//
|
|
|
|
if (!(tag & LARGE_RESOURCE_TAG)) {
|
|
size = (USHORT)(tag & SMALL_TAG_SIZE_MASK);
|
|
size += 1; // length of small tag
|
|
} else {
|
|
size = *(PUSHORT)(DeviceData + 1);
|
|
size += 3; // length of large tag
|
|
}
|
|
|
|
DeviceData += size;
|
|
tag = *DeviceData;
|
|
|
|
//
|
|
// Do we find the identifer resource tag?
|
|
//
|
|
|
|
if (tag == TAG_ANSI_ID) {
|
|
DeviceData++;
|
|
length = *(PUSHORT)DeviceData;
|
|
DeviceData += 2;
|
|
ansiBuffer = (PCHAR)ExAllocatePool(PagedPool, length+1);
|
|
if (ansiBuffer == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
RtlMoveMemory(ansiBuffer, DeviceData, length);
|
|
ansiBuffer[length] = 0;
|
|
RtlInitAnsiString(&ansiString, ansiBuffer);
|
|
RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
|
|
ExFreePool(ansiBuffer);
|
|
*Buffer = unicodeString.Buffer;
|
|
*BufferLength = unicodeString.Length + sizeof(WCHAR);
|
|
break;
|
|
}
|
|
|
|
} while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID));
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PipGetCompatibleDeviceId (
|
|
PUCHAR DeviceData,
|
|
ULONG IdIndex,
|
|
PWCHAR *Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the desired pnp isa id for the specified DeviceData
|
|
and Id index. If Id index = 0, the Hardware ID will be return; if id
|
|
index = n, the Nth compatible id will be returned.
|
|
|
|
Arguments:
|
|
|
|
DeviceData - supplies a pointer to the pnp isa device data.
|
|
|
|
IdIndex - supplies the index of the compatible id desired.
|
|
|
|
Buffer - supplies a pointer to variable to receive a pointer to the compatible Id.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_NO_MORE_ENTRIES;
|
|
UCHAR tag;
|
|
ULONG count = 0;
|
|
LONG size;
|
|
UNICODE_STRING unicodeString;
|
|
ANSI_STRING ansiString;
|
|
UCHAR eisaId[8];
|
|
ULONG id;
|
|
|
|
tag = *DeviceData;
|
|
|
|
#if DBG
|
|
|
|
//
|
|
// Make sure device data points to Logical Device Id tag
|
|
//
|
|
|
|
if ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID) {
|
|
DbgPrint("PipGetCompatibleDeviceId: DeviceData is not at Logical Id tag\n");
|
|
}
|
|
#endif
|
|
|
|
if (IdIndex == 0) {
|
|
|
|
//
|
|
// Caller is asking for hardware id
|
|
//
|
|
|
|
DeviceData++; // Skip tag
|
|
id = *(PULONG)DeviceData;
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
|
|
//
|
|
// caller is asking for compatible id
|
|
//
|
|
|
|
IdIndex--;
|
|
|
|
//
|
|
// Skip all the resource descriptors to find compatible Id descriptor
|
|
//
|
|
|
|
do {
|
|
|
|
//
|
|
// Determine the size of the BIOS resource descriptor and
|
|
// advance to next resource descriptor.
|
|
//
|
|
|
|
if (!(tag & LARGE_RESOURCE_TAG)) {
|
|
size = (USHORT)(tag & SMALL_TAG_SIZE_MASK);
|
|
size += 1; // length of small tag
|
|
} else {
|
|
size = *(PUSHORT)(DeviceData + 1);
|
|
size += 3; // length of large tag
|
|
}
|
|
|
|
DeviceData += size;
|
|
tag = *DeviceData;
|
|
|
|
//
|
|
// Do we reach the compatible ID descriptor?
|
|
//
|
|
|
|
if ((tag & SMALL_TAG_MASK) == TAG_COMPATIBLE_ID) {
|
|
if (count == IdIndex) {
|
|
id = *(PULONG)(DeviceData + 1);
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
} else {
|
|
count++;
|
|
}
|
|
}
|
|
|
|
} while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID));
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
PipDecompressEisaId(id, eisaId);
|
|
RtlInitAnsiString(&ansiString, eisaId);
|
|
RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
|
|
*Buffer = (PWCHAR)ExAllocatePool (
|
|
PagedPool,
|
|
sizeof(L"*") + sizeof(WCHAR) + unicodeString.Length
|
|
);
|
|
if (*Buffer) {
|
|
swprintf(*Buffer, L"*%s", unicodeString.Buffer);
|
|
} else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlFreeUnicodeString(&unicodeString);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PipQueryDeviceUniqueId (
|
|
PDEVICE_INFORMATION DeviceInfo,
|
|
PWCHAR *DeviceId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the unique id for the particular device.
|
|
|
|
Arguments:
|
|
|
|
DeviceData - Device data information for the specificied device.
|
|
|
|
DeviceId - supplies a pointer to a variable to receive device id.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Set up device's unique id.
|
|
// device unique id = SerialNumber of the card
|
|
//
|
|
|
|
*DeviceId = (PWCHAR)ExAllocatePool (
|
|
PagedPool,
|
|
(8 + 1) * sizeof(WCHAR) // serial number + null
|
|
);
|
|
if (*DeviceId) {
|
|
swprintf (*DeviceId,
|
|
L"%08X",
|
|
((PSERIAL_IDENTIFIER) (DeviceInfo->CardInformation->CardData))->SerialNumber
|
|
);
|
|
#if IDBG
|
|
{
|
|
ANSI_STRING ansiString;
|
|
UNICODE_STRING unicodeString;
|
|
|
|
RtlInitUnicodeString(&unicodeString, *DeviceId);
|
|
RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE);
|
|
DbgPrint("PnpIsa: return Unique Id = %s\n", ansiString.Buffer);
|
|
RtlFreeAnsiString(&ansiString);
|
|
}
|
|
#endif
|
|
} else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PipQueryDeviceId (
|
|
PDEVICE_INFORMATION DeviceInfo,
|
|
PWCHAR *DeviceId,
|
|
ULONG IdIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the device id for the particular device.
|
|
|
|
Arguments:
|
|
|
|
DeviceInfo - Device information for the specificied device.
|
|
|
|
DeviceId - supplies a pointer to a variable to receive the device id.
|
|
|
|
IdIndex - specifies device id or compatible id (0 - device id)
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PWSTR format;
|
|
ULONG size;
|
|
UCHAR eisaId[8];
|
|
UNICODE_STRING unicodeString;
|
|
ANSI_STRING ansiString;
|
|
|
|
//
|
|
// Set up device's id.
|
|
// device id = VenderId + Logical device number
|
|
//
|
|
|
|
if (DeviceInfo->CardInformation->NumberLogicalDevices == 1) {
|
|
format = L"ISAPNP\\%s";
|
|
size = sizeof(L"ISAPNP\\*") + sizeof(WCHAR);
|
|
} else {
|
|
format = L"ISAPNP\\%s_DEV%04X";
|
|
size = sizeof(L"ISAPNP\\_DEV") + 4 * sizeof(WCHAR) + sizeof(WCHAR);
|
|
}
|
|
PipDecompressEisaId(
|
|
((PSERIAL_IDENTIFIER) (DeviceInfo->CardInformation->CardData))->VenderId,
|
|
eisaId
|
|
);
|
|
RtlInitAnsiString(&ansiString, eisaId);
|
|
RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
|
|
size += unicodeString.Length;
|
|
*DeviceId = (PWCHAR)ExAllocatePool (PagedPool, size);
|
|
if (*DeviceId) {
|
|
swprintf (*DeviceId,
|
|
format,
|
|
unicodeString.Buffer,
|
|
DeviceInfo->LogicalDeviceNumber
|
|
);
|
|
#if IDBG
|
|
{
|
|
ANSI_STRING dbgAnsiString;
|
|
UNICODE_STRING dbgUnicodeString;
|
|
|
|
RtlInitUnicodeString(&dbgUnicodeString, *DeviceId);
|
|
RtlUnicodeStringToAnsiString(&dbgAnsiString, &dbgUnicodeString, TRUE);
|
|
DbgPrint("PnpIsa: return device Id = %s\n", dbgAnsiString.Buffer);
|
|
RtlFreeAnsiString(&dbgAnsiString);
|
|
}
|
|
#endif
|
|
} else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlFreeUnicodeString(&unicodeString);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PipQueryDeviceResources (
|
|
PDEVICE_INFORMATION DeviceInfo,
|
|
ULONG BusNumber,
|
|
PCM_RESOURCE_LIST *CmResources,
|
|
ULONG *Size
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the bus resources being used by the specified device
|
|
|
|
Arguments:
|
|
|
|
DeviceInfo - Device information for the specificied slot
|
|
|
|
BusNumber - should always be 0
|
|
|
|
CmResources - supplies a pointer to a variable to receive the device resource
|
|
data.
|
|
|
|
Size - Supplies a pointer to avariable to receive the size of device resource
|
|
data.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code.
|
|
|
|
--*/
|
|
{
|
|
ULONG length;
|
|
NTSTATUS status;
|
|
PCM_RESOURCE_LIST cmResources;
|
|
|
|
PipSelectLogicalDevice(DeviceInfo->CardInformation->CardSelectNumber,
|
|
DeviceInfo->LogicalDeviceNumber,
|
|
FALSE
|
|
);
|
|
|
|
status = PipReadDeviceBootResourceData (
|
|
BusNumber,
|
|
DeviceInfo->DeviceData,
|
|
&cmResources,
|
|
&length
|
|
);
|
|
|
|
//
|
|
// Put all cards into wait for key state.
|
|
//
|
|
|
|
PipWriteAddress(CONFIG_CONTROL_PORT);
|
|
PipWriteData(CONTROL_WAIT_FOR_KEY);
|
|
|
|
//
|
|
// Return results
|
|
//
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
if (length == 0) {
|
|
cmResources = NULL; // Just to make sure.
|
|
}
|
|
*CmResources = cmResources;
|
|
*Size = length;
|
|
#if IDBG
|
|
PipDumpCmResourceList(cmResources);
|
|
#endif
|
|
}
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PipQueryDeviceResourceRequirements (
|
|
PDEVICE_INFORMATION DeviceInfo,
|
|
ULONG BusNumber,
|
|
ULONG Slot,
|
|
PIO_RESOURCE_REQUIREMENTS_LIST *IoResources,
|
|
ULONG *Size
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the possible bus resources that this device may be
|
|
satisfied with.
|
|
|
|
Arguments:
|
|
|
|
DeviceData - Device data information for the specificied slot
|
|
|
|
BusNumber - Supplies the bus number
|
|
|
|
Slot - supplies the slot number of the BusNumber
|
|
|
|
IoResources - supplies a pointer to a variable to receive the IO resource
|
|
requirements list
|
|
|
|
Return Value:
|
|
|
|
The device control is completed
|
|
|
|
--*/
|
|
{
|
|
ULONG length = 0;
|
|
NTSTATUS status;
|
|
PUCHAR deviceData;
|
|
PIO_RESOURCE_REQUIREMENTS_LIST ioResources;
|
|
|
|
deviceData = DeviceInfo->DeviceData;
|
|
status = PbBiosResourcesToNtResources (
|
|
BusNumber,
|
|
Slot,
|
|
&deviceData,
|
|
&ioResources,
|
|
&length
|
|
);
|
|
|
|
//
|
|
// Return results
|
|
//
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
if (length == 0) {
|
|
ioResources = NULL; // Just ot make sure
|
|
}
|
|
*IoResources = ioResources;
|
|
*Size = length;
|
|
#if IDBG
|
|
PipDumpIoResourceList(ioResources);
|
|
#endif
|
|
}
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PipSetDeviceResources (
|
|
PDEVICE_INFORMATION DeviceInfo,
|
|
PCM_RESOURCE_LIST CmResources
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function configures the device to the specified device setttings
|
|
|
|
Arguments:
|
|
|
|
DeviceInfo - Device information for the specificied slot
|
|
|
|
CmResources - pointer to the desired resource list
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
PipSelectLogicalDevice(DeviceInfo->CardInformation->CardSelectNumber,
|
|
DeviceInfo->LogicalDeviceNumber,
|
|
FALSE
|
|
);
|
|
|
|
//
|
|
// Set resource settings for the device
|
|
//
|
|
|
|
status = PipWriteDeviceBootResourceData (
|
|
DeviceInfo->DeviceData,
|
|
(PCM_RESOURCE_LIST) CmResources
|
|
);
|
|
//
|
|
// Put all cards into wait for key state.
|
|
//
|
|
|
|
PipWriteAddress(CONFIG_CONTROL_PORT);
|
|
PipWriteData(CONTROL_WAIT_FOR_KEY);
|
|
|
|
return status;
|
|
}
|