556 lines
14 KiB
C
556 lines
14 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 "..\..\pnpbios\i386\pbios.h"
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PipGetCompatibleDeviceId (
|
|||
|
PUCHAR DeviceData,
|
|||
|
ULONG IdIndex,
|
|||
|
PWCHAR Buffer
|
|||
|
);
|
|||
|
|
|||
|
#define IDBG 1
|
|||
|
|
|||
|
#pragma alloc_text(PAGE,PipGetCompatibleDeviceId)
|
|||
|
#pragma alloc_text(PAGE,PiCtlQueryDeviceId)
|
|||
|
#pragma alloc_text(PAGE,PiCtlQueryDeviceUniqueId)
|
|||
|
#pragma alloc_text(PAGE,PiCtlQueryDeviceResources)
|
|||
|
#pragma alloc_text(PAGE,PiCtlQueryDeviceResourceRequirements)
|
|||
|
#pragma alloc_text(PAGE,PiCtlSetDeviceResources)
|
|||
|
|
|||
|
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 a buffer to receive 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;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
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
|
|||
|
//
|
|||
|
|
|||
|
while (tag != TAG_COMPLETE_END) {
|
|||
|
|
|||
|
//
|
|||
|
// 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++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// 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;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
PipDecompressEisaId(id, eisaId);
|
|||
|
RtlInitAnsiString(&ansiString, eisaId);
|
|||
|
RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
|
|||
|
swprintf(Buffer, L"PNPISA\\*%s", unicodeString.Buffer);
|
|||
|
RtlFreeUnicodeString(&unicodeString);
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PiCtlQueryDeviceUniqueId (
|
|||
|
PDEVICE_INFORMATION DeviceInfo,
|
|||
|
PHAL_DEVICE_CONTROL_CONTEXT Context
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function returns the unique id for the particular device.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceData - Device data information for the specificied device.
|
|||
|
|
|||
|
Context - Device control context of the request.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The device control is completed
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
PWCHAR deviceId;
|
|||
|
PUCHAR deviceData;
|
|||
|
ULONG eisaid;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Set up device's unique id.
|
|||
|
// device unique id = card series number + logical device eisa id in compressed form
|
|||
|
//
|
|||
|
|
|||
|
deviceId = (PWCHAR) Context->DeviceControl.Buffer;
|
|||
|
deviceData = DeviceInfo->DeviceData;
|
|||
|
|
|||
|
//
|
|||
|
// Make sure device data points to Logical Device Id tag
|
|||
|
//
|
|||
|
|
|||
|
if ((*deviceData & SMALL_TAG_MASK) != TAG_LOGICAL_ID) {
|
|||
|
|
|||
|
//
|
|||
|
// Can not get the eisa compressed id. Use logical device number instead.
|
|||
|
//
|
|||
|
#if DBG
|
|||
|
DbgPrint("PipGetCompatibleDeviceId: DeviceData is not at Logical Id tag\n");
|
|||
|
#endif
|
|||
|
eisaid = DeviceInfo->LogicalDeviceNumber;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Get the eisa compressed id for the logical device.
|
|||
|
//
|
|||
|
|
|||
|
deviceData++; // Skip tag
|
|||
|
eisaid = *(PULONG)deviceData;
|
|||
|
}
|
|||
|
swprintf (deviceId,
|
|||
|
L"%08x%08x",
|
|||
|
((PSERIAL_IDENTIFIER) (DeviceInfo->CardInformation->CardData))->SerialNumber,
|
|||
|
eisaid
|
|||
|
);
|
|||
|
#if IDBG
|
|||
|
{
|
|||
|
ANSI_STRING ansiString;
|
|||
|
UNICODE_STRING unicodeString;
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, (PWCHAR)Context->DeviceControl.Buffer);
|
|||
|
RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE);
|
|||
|
DbgPrint("Bus %x Slot %x Unique Id = %s\n",
|
|||
|
Context->Handler->BusNumber,
|
|||
|
DeviceInfoSlot(DeviceInfo),
|
|||
|
ansiString.Buffer
|
|||
|
);
|
|||
|
RtlFreeAnsiString(&ansiString);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
PipCompleteDeviceControl (STATUS_SUCCESS, Context, DeviceInfo);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PiCtlQueryDeviceId (
|
|||
|
PDEVICE_INFORMATION DeviceInfo,
|
|||
|
PHAL_DEVICE_CONTROL_CONTEXT Context
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function returns the device id for the particular device.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceInfo - Device information for the specificied device.
|
|||
|
|
|||
|
Context - Device control context of the request.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The device control is completed
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PWCHAR deviceId;
|
|||
|
ULONG idIndex;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Determine which device ID the caller wants back
|
|||
|
//
|
|||
|
|
|||
|
idIndex = *((PULONG) Context->DeviceControl.Buffer);
|
|||
|
|
|||
|
//
|
|||
|
// Call worker routine to get the desired Id.
|
|||
|
//
|
|||
|
|
|||
|
deviceId = (PWCHAR) Context->DeviceControl.Buffer;
|
|||
|
status = PipGetCompatibleDeviceId(DeviceInfo->DeviceData,
|
|||
|
idIndex,
|
|||
|
(PWCHAR) deviceId);
|
|||
|
|
|||
|
#if IDBG
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
ANSI_STRING ansiString;
|
|||
|
UNICODE_STRING unicodeString;
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, deviceId);
|
|||
|
RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE);
|
|||
|
DbgPrint("Bus %x Slot %x IdIndex %x Compatible Id = %s\n",
|
|||
|
Context->Handler->BusNumber,
|
|||
|
DeviceInfoSlot(DeviceInfo),
|
|||
|
idIndex,
|
|||
|
ansiString.Buffer
|
|||
|
);
|
|||
|
RtlFreeAnsiString(&ansiString);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
PipCompleteDeviceControl (status, Context, DeviceInfo);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PiCtlQueryDeviceResources (
|
|||
|
PDEVICE_INFORMATION DeviceInfo,
|
|||
|
PHAL_DEVICE_CONTROL_CONTEXT Context
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function completes the QUERY_DEVICE_RESOURCES DeviceControl
|
|||
|
which returns the bus resources being used by the specified device
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceInfo - Device information for the specificied slot
|
|||
|
|
|||
|
Context - Device control context of the request
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The device control is completed
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG length;
|
|||
|
PCM_RESOURCE_LIST cmResources;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// protect port access
|
|||
|
//
|
|||
|
|
|||
|
ExAcquireFastMutex(&PipPortMutex);
|
|||
|
|
|||
|
PipSelectLogicalDevice(DeviceInfo->CardInformation->CardSelectNumber,
|
|||
|
DeviceInfo->LogicalDeviceNumber
|
|||
|
);
|
|||
|
|
|||
|
status = PipReadDeviceBootResourceData (
|
|||
|
Context->Handler->BusNumber,
|
|||
|
DeviceInfo->DeviceData,
|
|||
|
&cmResources,
|
|||
|
&length
|
|||
|
);
|
|||
|
|
|||
|
PipWriteAddress(ACTIVATE_PORT);
|
|||
|
PipWriteData(0);
|
|||
|
|
|||
|
//
|
|||
|
// Put all cards into wait for key state.
|
|||
|
//
|
|||
|
|
|||
|
PipWriteAddress(CONFIG_CONTROL_PORT);
|
|||
|
PipWriteData(CONTROL_WAIT_FOR_KEY);
|
|||
|
|
|||
|
ExReleaseFastMutex(&PipPortMutex);
|
|||
|
|
|||
|
//
|
|||
|
// Return results
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
if (length == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// If resource info is not available, return an empty CM_RESOURCE_LIST
|
|||
|
//
|
|||
|
|
|||
|
cmResources = (PCM_RESOURCE_LIST) ExAllocatePoolWithTag (
|
|||
|
PagedPool, sizeof(CM_RESOURCE_LIST), 'iPnP');
|
|||
|
if (!cmResources) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
goto exitLocal;
|
|||
|
} else {
|
|||
|
cmResources->Count = 0;
|
|||
|
cmResources->List[0].InterfaceType = Context->RootHandler->InterfaceType;
|
|||
|
cmResources->List[0].BusNumber = Context->RootHandler->BusNumber;
|
|||
|
cmResources->List[0].PartialResourceList.Version = 0;
|
|||
|
cmResources->List[0].PartialResourceList.Revision = 0;
|
|||
|
cmResources->List[0].PartialResourceList.Count = 0;
|
|||
|
length = sizeof(CM_RESOURCE_LIST);
|
|||
|
}
|
|||
|
}
|
|||
|
if (length > *Context->DeviceControl.BufferLength) {
|
|||
|
status = STATUS_BUFFER_TOO_SMALL;
|
|||
|
} else {
|
|||
|
RtlCopyMemory (Context->DeviceControl.Buffer, cmResources, length);
|
|||
|
}
|
|||
|
*Context->DeviceControl.BufferLength = length;
|
|||
|
#if IDBG
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
PipDumpCmResourceList(cmResources, DeviceInfoSlot(DeviceInfo));
|
|||
|
}
|
|||
|
#endif
|
|||
|
ExFreePool(cmResources);
|
|||
|
}
|
|||
|
exitLocal:
|
|||
|
PipCompleteDeviceControl (status, Context, DeviceInfo);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PiCtlQueryDeviceResourceRequirements (
|
|||
|
PDEVICE_INFORMATION DeviceInfo,
|
|||
|
PHAL_DEVICE_CONTROL_CONTEXT Context
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function completes the QUERY_DEVICE_RESOURCE_REQUIREMENTS DeviceControl
|
|||
|
which returns the possible bus resources that this device may be
|
|||
|
satisfied with.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceData - Device data information for the specificied slot
|
|||
|
|
|||
|
Context - Device control context of the request
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The device control is completed
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG length = 0;
|
|||
|
PIO_RESOURCE_REQUIREMENTS_LIST ioResources = NULL;
|
|||
|
NTSTATUS status;
|
|||
|
PUCHAR deviceData;
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
deviceData = DeviceInfo->DeviceData;
|
|||
|
status = PbBiosResourcesToNtResources (
|
|||
|
Context->RootHandler->BusNumber,
|
|||
|
DeviceInfoSlot(DeviceInfo),
|
|||
|
&deviceData,
|
|||
|
&ioResources,
|
|||
|
&length
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Return results
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
if (length == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// If resource info is not available, return an empty CM_RESOURCE_LIST
|
|||
|
//
|
|||
|
|
|||
|
ioResources = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePoolWithTag (
|
|||
|
PagedPool, sizeof(IO_RESOURCE_REQUIREMENTS_LIST), 'bPnP');
|
|||
|
if (!ioResources) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
goto exitLocal;
|
|||
|
} else {
|
|||
|
ioResources->ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
|
|||
|
ioResources->InterfaceType = Context->RootHandler->InterfaceType;
|
|||
|
ioResources->BusNumber = Context->RootHandler->BusNumber;
|
|||
|
ioResources->SlotNumber = DeviceInfoSlot(DeviceInfo);
|
|||
|
ioResources->Reserved[0] = 0;
|
|||
|
ioResources->Reserved[1] = 0;
|
|||
|
ioResources->Reserved[2] = 0;
|
|||
|
ioResources->AlternativeLists = 0;
|
|||
|
ioResources->List[0].Version = 1;
|
|||
|
ioResources->List[0].Revision = 1;
|
|||
|
ioResources->List[0].Count = 0;
|
|||
|
length = sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
|
|||
|
}
|
|||
|
}
|
|||
|
if (length > *Context->DeviceControl.BufferLength) {
|
|||
|
status = STATUS_BUFFER_TOO_SMALL;
|
|||
|
} else {
|
|||
|
RtlCopyMemory (Context->DeviceControl.Buffer, ioResources, length);
|
|||
|
}
|
|||
|
*Context->DeviceControl.BufferLength = length;
|
|||
|
#if IDBG
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
PipDumpIoResourceList(ioResources);
|
|||
|
}
|
|||
|
#endif
|
|||
|
ExFreePool(ioResources);
|
|||
|
}
|
|||
|
exitLocal:
|
|||
|
PipCompleteDeviceControl (status, Context, DeviceInfo);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PiCtlSetDeviceResources (
|
|||
|
PDEVICE_INFORMATION DeviceInfo,
|
|||
|
PHAL_DEVICE_CONTROL_CONTEXT Context
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function completes the SET_DEVICE_RESOURCES DeviceControl
|
|||
|
which configures the device to the specified device setttings
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceInfo - Device information for the specificied slot
|
|||
|
|
|||
|
Context - Device control context of the request
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The device control is completed
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Protect port access
|
|||
|
//
|
|||
|
|
|||
|
ExAcquireFastMutex(&PipPortMutex);
|
|||
|
|
|||
|
PipSelectLogicalDevice(DeviceInfo->CardInformation->CardSelectNumber,
|
|||
|
DeviceInfo->LogicalDeviceNumber
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Set resource settings for the device
|
|||
|
//
|
|||
|
|
|||
|
status = PipWriteDeviceBootResourceData (
|
|||
|
DeviceInfo->DeviceData,
|
|||
|
(PCM_RESOURCE_LIST) Context->DeviceControl.Buffer
|
|||
|
);
|
|||
|
//
|
|||
|
// Put all cards into wait for key state.
|
|||
|
//
|
|||
|
|
|||
|
PipWriteAddress(CONFIG_CONTROL_PORT);
|
|||
|
PipWriteData(CONTROL_WAIT_FOR_KEY);
|
|||
|
|
|||
|
ExReleaseFastMutex(&PipPortMutex);
|
|||
|
PipCompleteDeviceControl (status, Context, DeviceInfo);
|
|||
|
}
|