windows-nt/Source/XPSP1/NT/base/ntos/io/pnpmgr/pnpeisa.c
2020-09-26 16:20:57 +08:00

390 lines
12 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
PnpEisa.c
Abstract:
This file implements Eisa related code.
Author:
Shie-Lin Tzong (shielint)
Environment:
Kernel Mode.
Notes:
Revision History:
--*/
#include "pnpmgrp.h"
#pragma hdrstop
#ifdef POOL_TAGGING
#undef ExAllocatePool
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'iepP')
#endif
#define EISA_DEVICE_NODE_NAME L"EisaResources"
#define BUFFER_LENGTH 50
NTSTATUS
EisaGetEisaDevicesResources (
OUT PCM_RESOURCE_LIST *ResourceList,
OUT PULONG ResourceLength
);
NTSTATUS
EisaBuildSlotsResources (
IN ULONG SlotMasks,
IN ULONG NumberMasks,
OUT PCM_RESOURCE_LIST *Resource,
OUT ULONG *Length
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, EisaBuildEisaDeviceNode)
#pragma alloc_text(INIT, EisaGetEisaDevicesResources)
#pragma alloc_text(INIT, EisaBuildSlotsResources)
#endif
NTSTATUS
EisaBuildEisaDeviceNode (
VOID
)
/*++
Routine Description:
This routine build an registry key to report eisa resources to arbiters.
Arguments:
None.
Return Value:
NTSTATUS code.
--*/
{
NTSTATUS status;
ULONG disposition, tmpValue;
WCHAR buffer[BUFFER_LENGTH];
UNICODE_STRING unicodeString;
HANDLE rootHandle, deviceHandle, instanceHandle, logConfHandle;
PCM_RESOURCE_LIST resourceList;
ULONG resourceLength;
status = EisaGetEisaDevicesResources(&resourceList, &resourceLength);
if (!NT_SUCCESS(status) || resourceList == NULL) {
return STATUS_UNSUCCESSFUL;
}
PiWstrToUnicodeString(&unicodeString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\Root");
status = IopOpenRegistryKeyEx( &rootHandle,
NULL,
&unicodeString,
KEY_ALL_ACCESS
);
if (!NT_SUCCESS(status)) {
if (resourceList) {
ExFreePool (resourceList);
}
return status;
}
PiWstrToUnicodeString(&unicodeString, EISA_DEVICE_NODE_NAME);
status = IopCreateRegistryKeyEx( &deviceHandle,
rootHandle,
&unicodeString,
KEY_ALL_ACCESS,
REG_OPTION_NON_VOLATILE,
NULL
);
ZwClose(rootHandle);
if (!NT_SUCCESS(status)) {
if (resourceList) {
ExFreePool (resourceList);
}
return status;
}
PiWstrToUnicodeString( &unicodeString, L"0000" );
status = IopCreateRegistryKeyEx( &instanceHandle,
deviceHandle,
&unicodeString,
KEY_ALL_ACCESS,
REG_OPTION_NON_VOLATILE,
&disposition );
ZwClose(deviceHandle);
if (NT_SUCCESS(status)) {
//
// If the key already exists because it was explicitly migrated
// during textmode setup, we should still consider it a "new key".
//
if (disposition != REG_CREATED_NEW_KEY) {
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
status = IopGetRegistryValue(instanceHandle,
REGSTR_VALUE_MIGRATED,
&keyValueInformation);
if (NT_SUCCESS(status)) {
if ((keyValueInformation->Type == REG_DWORD) &&
(keyValueInformation->DataLength == sizeof(ULONG)) &&
((*(PULONG)KEY_VALUE_DATA(keyValueInformation)) != 0)) {
disposition = REG_CREATED_NEW_KEY;
}
ExFreePool(keyValueInformation);
PiWstrToUnicodeString(&unicodeString, REGSTR_VALUE_MIGRATED);
ZwDeleteValueKey(instanceHandle, &unicodeString);
}
}
if (disposition == REG_CREATED_NEW_KEY) {
PiWstrToUnicodeString( &unicodeString, L"DeviceDesc" );
wcsncpy(buffer, L"Device to report Eisa Slot Resources", sizeof(buffer) / sizeof(WCHAR));
buffer[(sizeof(buffer) / sizeof(WCHAR)) - 1] = UNICODE_NULL;
ZwSetValueKey(instanceHandle,
&unicodeString,
0,
REG_SZ,
buffer,
(ULONG)((wcslen(buffer) + 1) * sizeof(WCHAR))
);
PiWstrToUnicodeString( &unicodeString, L"HardwareID" );
RtlZeroMemory(buffer, BUFFER_LENGTH * sizeof(WCHAR));
wcsncpy(buffer, L"*Eisa_Resource_Device", sizeof(buffer) / sizeof(WCHAR));
buffer[(sizeof(buffer) / sizeof(WCHAR)) - 1] = UNICODE_NULL;
ZwSetValueKey(instanceHandle,
&unicodeString,
0,
REG_MULTI_SZ,
buffer,
(ULONG)((wcslen(buffer) + 2) * sizeof(WCHAR))
);
PiWstrToUnicodeString(&unicodeString, REGSTR_VALUE_CONFIG_FLAGS);
tmpValue = 0;
ZwSetValueKey(instanceHandle,
&unicodeString,
TITLE_INDEX_VALUE,
REG_DWORD,
&tmpValue,
sizeof(tmpValue)
);
}
PiWstrToUnicodeString( &unicodeString, REGSTR_KEY_LOGCONF );
status = IopCreateRegistryKeyEx( &logConfHandle,
instanceHandle,
&unicodeString,
KEY_ALL_ACCESS,
REG_OPTION_NON_VOLATILE,
NULL
);
ZwClose(instanceHandle);
if (NT_SUCCESS(status)) {
PiWstrToUnicodeString( &unicodeString, REGSTR_VAL_BOOTCONFIG );
status = ZwSetValueKey(logConfHandle,
&unicodeString,
0,
REG_RESOURCE_LIST,
resourceList,
resourceLength
);
ZwClose(logConfHandle);
}
}
if (resourceList) {
ExFreePool (resourceList);
}
return status;
}
NTSTATUS
EisaGetEisaDevicesResources (
OUT PCM_RESOURCE_LIST *ResourceList,
OUT PULONG ResourceLength
)
/*++
Routine Description:
This routine builds a cm resource list for all the eisa slots.
Arguments:
None.
Return Value:
A CmResourceList.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
HANDLE handle;
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
UNICODE_STRING unicodeString;
ULONG slotMasks = 0, numberMasks = 0, i;
*ResourceList = NULL;
*ResourceLength = 0;
//
// Open LocalMachine\Hardware\Description
//
//PiWstrToUnicodeString(&unicodeString, L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM\\EisaAdapter\\0");
PiWstrToUnicodeString(&unicodeString, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\EisaAdapter");
status = IopOpenRegistryKeyEx( &handle,
NULL,
&unicodeString,
KEY_READ
);
if (NT_SUCCESS(status)) {
status = IopGetRegistryValue(handle,
L"Configuration Data",
&keyValueInformation
);
if (NT_SUCCESS(status)) {
PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor;
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialResourceDescriptor;
resourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)
((PUCHAR) keyValueInformation + keyValueInformation->DataOffset);
if ((keyValueInformation->DataLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) &&
(resourceDescriptor->PartialResourceList.Count > 0) ) {
LONG eisaInfoLength;
PCM_EISA_SLOT_INFORMATION eisaInfo;
partialResourceDescriptor = resourceDescriptor->PartialResourceList.PartialDescriptors;
if (partialResourceDescriptor->Type == CmResourceTypeDeviceSpecific) {
eisaInfo = (PCM_EISA_SLOT_INFORMATION)
((PUCHAR)partialResourceDescriptor + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
eisaInfoLength = (LONG)partialResourceDescriptor->u.DeviceSpecificData.DataSize;
//
// Parse the eisa slot info to find the eisa slots with device installed.
//
for (i = 0; i < 0x10 && eisaInfoLength > 0; i++) {
if (eisaInfo->ReturnCode == EISA_INVALID_SLOT) {
break;
}
if (eisaInfo->ReturnCode != EISA_EMPTY_SLOT && (i != 0)) {
slotMasks |= (1 << i);
numberMasks++;
}
if (eisaInfo->ReturnCode == EISA_EMPTY_SLOT) {
eisaInfoLength -= sizeof(CM_EISA_SLOT_INFORMATION);
eisaInfo++;
} else {
eisaInfoLength -= sizeof(CM_EISA_SLOT_INFORMATION) + eisaInfo->NumberFunctions * sizeof(CM_EISA_FUNCTION_INFORMATION);
eisaInfo = (PCM_EISA_SLOT_INFORMATION)
((PUCHAR)eisaInfo + eisaInfo->NumberFunctions * sizeof(CM_EISA_FUNCTION_INFORMATION) +
sizeof(CM_EISA_SLOT_INFORMATION));
}
}
if (slotMasks) {
status = EisaBuildSlotsResources(slotMasks, numberMasks, ResourceList, ResourceLength);
}
}
}
ExFreePool(keyValueInformation);
}
ZwClose(handle);
}
return status;
}
NTSTATUS
EisaBuildSlotsResources (
IN ULONG SlotMasks,
IN ULONG NumberMasks,
OUT PCM_RESOURCE_LIST *Resources,
OUT ULONG *Length
)
/*++
Routine Description:
This routine build a cm resource list for all the io resources used
by the eisa devices.
Arguments:
SlotMask - a mask to indicate the valid eisa slot.
Return Value:
A pointer to a CM_RESOURCE_LIST.
--*/
{
PCM_RESOURCE_LIST resources = NULL;
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDesc;
ULONG slot;
*Length = sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (NumberMasks - 1);
resources = ExAllocatePool(PagedPool, *Length);
if (resources) {
resources->Count = 1;
resources->List[0].InterfaceType = Eisa;
resources->List[0].BusNumber = 0;
resources->List[0].PartialResourceList.Version = 0;
resources->List[0].PartialResourceList.Revision = 0;
resources->List[0].PartialResourceList.Count = NumberMasks;
partialDesc = resources->List[0].PartialResourceList.PartialDescriptors;
slot = 0; // ignore slot 0
while (SlotMasks) {
SlotMasks >>= 1;
slot++;
if (SlotMasks & 1) {
partialDesc->Type = CmResourceTypePort;
partialDesc->ShareDisposition = CmResourceShareDeviceExclusive;
partialDesc->Flags = CM_RESOURCE_PORT_16_BIT_DECODE + CM_RESOURCE_PORT_IO;
partialDesc->u.Port.Start.LowPart = slot << 12;
partialDesc->u.Port.Start.HighPart = 0;
partialDesc->u.Port.Length = 0x1000;
partialDesc++;
}
}
*Resources = resources;
return STATUS_SUCCESS;
} else {
return STATUS_NO_MEMORY;
}
}