681 lines
16 KiB
C
681 lines
16 KiB
C
/*++
|
||
|
||
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;
|
||
}
|